Add update to ejurgensen's pair_ap library. Thanks as always.
This commit is contained in:
@@ -108,7 +108,7 @@ make_request(const char *url, const void *data, size_t len, const char *content_
|
||||
else if (pair_type == PAIR_CLIENT_HOMEKIT_TRANSIENT)
|
||||
evrtsp_add_header(req->output_headers, "X-Apple-HKP", "4");
|
||||
|
||||
printf("Making request %d to '%s'... ", cseq, url);
|
||||
printf("Making request %d to '%s' (len %zu)... ", cseq, url, len);
|
||||
|
||||
return evrtsp_make_request(evcon, req, EVRTSP_REQ_POST, url);
|
||||
}
|
||||
@@ -136,7 +136,7 @@ make_request_options(const char *url, const void *data, size_t len, const char *
|
||||
// evrtsp_add_header(req->output_headers, "Active-Remote", ACTIVE_REMOTE);
|
||||
evrtsp_add_header(req->output_headers, "X-Apple-HKP", "3");
|
||||
|
||||
printf("Making request %d to '%s'... ", cseq, url);
|
||||
printf("Making request %d to '%s' (len %zu)... ", cseq, url, len);
|
||||
|
||||
return evrtsp_make_request(evcon, req, EVRTSP_REQ_OPTIONS, url);
|
||||
}
|
||||
|
||||
@@ -367,7 +367,7 @@ int
|
||||
hash_ab(enum hash_alg alg, unsigned char *md, const unsigned char *m1, int m1_len, const unsigned char *m2, int m2_len);
|
||||
|
||||
bnum
|
||||
H_nn_pad(enum hash_alg alg, const bnum n1, const bnum n2);
|
||||
H_nn_pad(enum hash_alg alg, const bnum n1, const bnum n2, int padded_len);
|
||||
|
||||
bnum
|
||||
H_ns(enum hash_alg alg, const bnum n, const unsigned char *bytes, int len_bytes);
|
||||
@@ -384,4 +384,7 @@ hash_num(enum hash_alg alg, const bnum n, unsigned char *dest);
|
||||
#ifdef DEBUG_PAIR
|
||||
void
|
||||
hexdump(const char *msg, uint8_t *mem, size_t len);
|
||||
|
||||
void
|
||||
bnum_dump(const char *msg, bnum n);
|
||||
#endif
|
||||
|
||||
+24
-10
@@ -25,6 +25,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h> // for isprint()
|
||||
#include <assert.h>
|
||||
|
||||
#include <sodium.h>
|
||||
|
||||
@@ -188,24 +189,27 @@ hash_ab(enum hash_alg alg, unsigned char *md, const unsigned char *m1, int m1_le
|
||||
return hash_final(alg, &ctx, md);
|
||||
}
|
||||
|
||||
// See rfc5054 PAD()
|
||||
bnum
|
||||
H_nn_pad(enum hash_alg alg, const bnum n1, const bnum n2)
|
||||
H_nn_pad(enum hash_alg alg, const bnum n1, const bnum n2, int padded_len)
|
||||
{
|
||||
bnum bn;
|
||||
unsigned char *bin;
|
||||
unsigned char buff[SHA512_DIGEST_LENGTH];
|
||||
int len_n1 = bnum_num_bytes(n1);
|
||||
int len_n2 = bnum_num_bytes(n2);
|
||||
int nbytes = 2 * len_n1;
|
||||
int nbytes = 2 * padded_len;
|
||||
int offset_n1 = padded_len - len_n1;
|
||||
int offset_n2 = nbytes - len_n2;
|
||||
|
||||
if ((len_n2 < 1) || (len_n2 > len_n1))
|
||||
return 0;
|
||||
assert(len_n1 <= padded_len);
|
||||
assert(len_n2 <= padded_len);
|
||||
|
||||
bin = calloc( 1, nbytes );
|
||||
bin = calloc(1, nbytes);
|
||||
|
||||
bnum_bn2bin(n1, bin, len_n1);
|
||||
bnum_bn2bin(n2, bin + nbytes - len_n2, len_n2);
|
||||
hash( alg, bin, nbytes, buff );
|
||||
bnum_bn2bin(n1, bin + offset_n1, len_n1);
|
||||
bnum_bn2bin(n2, bin + offset_n2, len_n2);
|
||||
hash(alg, bin, nbytes, buff);
|
||||
free(bin);
|
||||
bnum_bin2bn(bn, buff, hash_length(alg));
|
||||
return bn;
|
||||
@@ -221,8 +225,8 @@ H_ns(enum hash_alg alg, const bnum n, const unsigned char *bytes, int len_bytes)
|
||||
unsigned char *bin = malloc(nbytes);
|
||||
|
||||
bnum_bn2bin(n, bin, len_n);
|
||||
memcpy( bin + len_n, bytes, len_bytes );
|
||||
hash( alg, bin, nbytes, buff );
|
||||
memcpy(bin + len_n, bytes, len_bytes);
|
||||
hash(alg, bin, nbytes, buff);
|
||||
free(bin);
|
||||
bnum_bin2bn(bn, buff, hash_length(alg));
|
||||
return bn;
|
||||
@@ -289,6 +293,16 @@ hexdump(const char *msg, uint8_t *mem, size_t len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
bnum_dump(const char *msg, bnum n)
|
||||
{
|
||||
int len_n = bnum_num_bytes(n);
|
||||
uint8_t *bin = calloc(1, len_n);
|
||||
bnum_bn2bin(n, bin, len_n);
|
||||
hexdump(msg, bin, len_n);
|
||||
free(bin);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define PAIR_AP_VERSION_MAJOR 0
|
||||
#define PAIR_AP_VERSION_MINOR 10
|
||||
#define PAIR_AP_VERSION_MINOR 12
|
||||
|
||||
#define PAIR_AP_DEVICE_ID_LEN_MAX 64
|
||||
|
||||
|
||||
@@ -60,6 +60,7 @@ typedef struct
|
||||
{
|
||||
bnum N;
|
||||
bnum g;
|
||||
int N_len;
|
||||
} NGConstant;
|
||||
|
||||
struct SRPUser
|
||||
@@ -122,6 +123,8 @@ new_ng(SRP_NGType ng_type, const char *n_hex, const char *g_hex)
|
||||
bnum_hex2bn(ng->N, n_hex);
|
||||
bnum_hex2bn(ng->g, g_hex);
|
||||
|
||||
ng->N_len = bnum_num_bytes(ng->N);
|
||||
|
||||
return ng;
|
||||
}
|
||||
|
||||
@@ -348,7 +351,7 @@ srp_user_process_challenge(struct SRPUser *usr, const unsigned char *bytes_s, in
|
||||
|
||||
bnum_bin2bn(s, bytes_s, len_s);
|
||||
bnum_bin2bn(B, bytes_B, len_B);
|
||||
k = H_nn_pad(usr->alg, usr->ng->N, usr->ng->g);
|
||||
k = H_nn_pad(usr->alg, usr->ng->N, usr->ng->g, usr->ng->N_len);
|
||||
bnum_new(v);
|
||||
bnum_new(tmp1);
|
||||
bnum_new(tmp2);
|
||||
@@ -357,7 +360,7 @@ srp_user_process_challenge(struct SRPUser *usr, const unsigned char *bytes_s, in
|
||||
if (!s || !B || !k || !v || !tmp1 || !tmp2 || !tmp3)
|
||||
goto cleanup1;
|
||||
|
||||
u = H_nn_pad(usr->alg, usr->A, B);
|
||||
u = H_nn_pad(usr->alg, usr->A, B, usr->ng->N_len);
|
||||
x = calculate_x(usr->alg, s, usr->username, usr->password, usr->password_len);
|
||||
if (!u || !x)
|
||||
goto cleanup2;
|
||||
|
||||
+79
-23
@@ -55,6 +55,8 @@
|
||||
#define REQUEST_BUFSIZE 4096
|
||||
#define ENCRYPTED_LEN_MAX 0x400
|
||||
|
||||
// #define DEBUG_SHORT_A 1
|
||||
|
||||
enum pair_keys
|
||||
{
|
||||
PAIR_SETUP_MSG01 = 0,
|
||||
@@ -140,6 +142,7 @@ typedef enum
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int N_len;
|
||||
bnum N;
|
||||
bnum g;
|
||||
} NGConstant;
|
||||
@@ -184,6 +187,7 @@ struct SRPVerifier
|
||||
|
||||
struct NGHex
|
||||
{
|
||||
int N_len;
|
||||
const char *n_hex;
|
||||
const char *g_hex;
|
||||
};
|
||||
@@ -192,6 +196,7 @@ struct NGHex
|
||||
static struct NGHex global_Ng_constants[] =
|
||||
{
|
||||
{ /* 2048 */
|
||||
256,
|
||||
"AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC3192943DB56050A37329CBB4"
|
||||
"A099ED8193E0757767A13DD52312AB4B03310DCD7F48A9DA04FD50E8083969EDB767B0CF60"
|
||||
"95179A163AB3661A05FBD5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF"
|
||||
@@ -202,6 +207,7 @@ static struct NGHex global_Ng_constants[] =
|
||||
"2"
|
||||
},
|
||||
{ /* 3072 */
|
||||
384,
|
||||
"FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74020BBEA63B"
|
||||
"139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F14374FE1356D6D51C245E485"
|
||||
"B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7EDEE386BFB5A899FA5AE9F24117C4B1F"
|
||||
@@ -215,7 +221,7 @@ static struct NGHex global_Ng_constants[] =
|
||||
"D120A93AD2CAFFFFFFFFFFFFFFFF",
|
||||
"5"
|
||||
},
|
||||
{0,0} /* null sentinel */
|
||||
{0} /* null sentinel */
|
||||
};
|
||||
|
||||
|
||||
@@ -226,13 +232,17 @@ new_ng(SRP_NGType ng_type, const char *n_hex, const char *g_hex)
|
||||
|
||||
if ( ng_type != SRP_NG_CUSTOM )
|
||||
{
|
||||
n_hex = global_Ng_constants[ ng_type ].n_hex;
|
||||
g_hex = global_Ng_constants[ ng_type ].g_hex;
|
||||
n_hex = global_Ng_constants[ng_type].n_hex;
|
||||
g_hex = global_Ng_constants[ng_type].g_hex;
|
||||
}
|
||||
|
||||
bnum_hex2bn(ng->N, n_hex);
|
||||
bnum_hex2bn(ng->g, g_hex);
|
||||
|
||||
ng->N_len = bnum_num_bytes(ng->N);
|
||||
|
||||
assert(ng_type == SRP_NG_CUSTOM || ng->N_len == global_Ng_constants[ng_type].N_len);
|
||||
|
||||
return ng;
|
||||
}
|
||||
|
||||
@@ -247,6 +257,15 @@ free_ng(NGConstant * ng)
|
||||
free(ng);
|
||||
}
|
||||
|
||||
static int
|
||||
N_len(SRP_NGType ng_type)
|
||||
{
|
||||
if (ng_type == SRP_NG_CUSTOM)
|
||||
return -1;
|
||||
|
||||
return global_Ng_constants[ng_type].N_len;
|
||||
}
|
||||
|
||||
static bnum
|
||||
calculate_x(enum hash_alg alg, const bnum salt, const char *username, const unsigned char *password, int password_len)
|
||||
{
|
||||
@@ -401,13 +420,27 @@ srp_user_get_session_key(struct SRPUser *usr, int *key_length)
|
||||
return usr->session_key;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SHORT_A
|
||||
// This value of "a" will yield a 383 byte A
|
||||
static uint8_t short_a[] = {
|
||||
0xef, 0xb5, 0x93, 0xf5, 0x03, 0x97, 0x69, 0x8e, 0x15, 0xed, 0xee, 0x5b, 0xf2, 0xf9, 0x23, 0x6c,
|
||||
0xf0, 0x59, 0x6c, 0xe2, 0x77, 0xf2, 0x14, 0x16, 0xac, 0x99, 0xfa, 0x31, 0xae, 0x2b, 0xd3, 0x41,
|
||||
};
|
||||
#endif
|
||||
|
||||
/* Output: username, bytes_A, len_A */
|
||||
static void
|
||||
srp_user_start_authentication(struct SRPUser *usr, const char **username,
|
||||
const unsigned char **bytes_A, int *len_A)
|
||||
{
|
||||
bnum_random(usr->a, 256);
|
||||
// BN_hex2bn(&(usr->a), "D929DFB605687233C9E9030C2280156D03BDB9FDCF3CCE3BC27D9CCFCB5FF6A1");
|
||||
bnum_random(usr->a, 256);
|
||||
#ifdef DEBUG_SHORT_A
|
||||
bnum_bin2bn(usr->a, short_a, sizeof(short_a));
|
||||
#endif
|
||||
#ifdef DEBUG_PAIR
|
||||
bnum_dump("Random value of usr->a:\n", usr->a);
|
||||
#endif
|
||||
|
||||
bnum_modexp(usr->A, usr->ng->g, usr->a, usr->ng->N);
|
||||
|
||||
@@ -443,7 +476,8 @@ srp_user_process_challenge(struct SRPUser *usr, const unsigned char *bytes_s, in
|
||||
|
||||
bnum_bin2bn(s, bytes_s, len_s);
|
||||
bnum_bin2bn(B, bytes_B, len_B);
|
||||
k = H_nn_pad(usr->alg, usr->ng->N, usr->ng->g);
|
||||
|
||||
k = H_nn_pad(usr->alg, usr->ng->N, usr->ng->g, usr->ng->N_len);
|
||||
|
||||
bnum_new(v);
|
||||
bnum_new(tmp1);
|
||||
@@ -453,7 +487,7 @@ srp_user_process_challenge(struct SRPUser *usr, const unsigned char *bytes_s, in
|
||||
if (!s || !B || !k || !v || !tmp1 || !tmp2 || !tmp3)
|
||||
goto cleanup1;
|
||||
|
||||
u = H_nn_pad(usr->alg, usr->A, B);
|
||||
u = H_nn_pad(usr->alg, usr->A, B, usr->ng->N_len);
|
||||
x = calculate_x(usr->alg, s, usr->username, usr->password, usr->password_len);
|
||||
if (!u || !x)
|
||||
goto cleanup2;
|
||||
@@ -535,6 +569,9 @@ srp_create_salted_verification_key(enum hash_alg alg,
|
||||
goto error;
|
||||
|
||||
bnum_random(s, 128); // MODIFIED from csrp's BN_rand(s, 32, -1, 0)
|
||||
#ifdef DEBUG_PAIR
|
||||
bnum_dump("Random value of s:\n", s);
|
||||
#endif
|
||||
|
||||
x = calculate_x(alg, s, username, password, len_password);
|
||||
if (!x)
|
||||
@@ -599,8 +636,11 @@ srp_verifier_start_authentication(enum hash_alg alg, SRP_NGType ng_type,
|
||||
bnum_bin2bn(v, bytes_v, len_v);
|
||||
|
||||
bnum_random(b, 256); // MODIFIED from BN_rand(b, 256, -1, 0)
|
||||
#ifdef DEBUG_PAIR
|
||||
bnum_dump("Random value of b:\n", b);
|
||||
#endif
|
||||
|
||||
k = H_nn_pad(alg, ng->N, ng->g); // MODIFIED from H_nn(alg, ng->N, ng->g)
|
||||
k = H_nn_pad(alg, ng->N, ng->g, ng->N_len); // MODIFIED from H_nn(alg, ng->N, ng->g)
|
||||
if (!k)
|
||||
goto error;
|
||||
|
||||
@@ -708,8 +748,8 @@ srp_verifier_new(enum hash_alg alg, SRP_NGType ng_type, const char *username,
|
||||
if (bnum_is_zero(tmp1))
|
||||
goto error;
|
||||
|
||||
k = H_nn_pad(alg, ng->N, ng->g); // MODIFIED from H_nn(alg, ng->N, ng->g)
|
||||
u = H_nn_pad(alg, A, B); // MODIFIED from H_nn(alg, A, B)
|
||||
k = H_nn_pad(alg, ng->N, ng->g, ng->N_len); // MODIFIED from H_nn(alg, ng->N, ng->g)
|
||||
u = H_nn_pad(alg, A, B, ng->N_len); // MODIFIED from H_nn(alg, A, B)
|
||||
|
||||
// S = (A *(v^u)) ^ b
|
||||
bnum_modexp(tmp1, v, u, ng->N);
|
||||
@@ -1163,6 +1203,11 @@ client_setup_new(struct pair_setup_context *handle, const char *pin, pair_cb add
|
||||
|
||||
crypto_sign_keypair(sctx->public_key, sctx->private_key);
|
||||
|
||||
#ifdef DEBUG_PAIR
|
||||
hexdump("Client public key:\n", sctx->public_key, sizeof(sctx->public_key));
|
||||
hexdump("Client private key:\n", sctx->private_key, sizeof(sctx->private_key));
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1397,18 +1442,24 @@ client_setup_response1(struct pair_setup_context *handle, const uint8_t *data, s
|
||||
}
|
||||
|
||||
pk = pair_tlv_get_value(response, TLVType_PublicKey);
|
||||
salt = pair_tlv_get_value(response, TLVType_Salt);
|
||||
if (!pk || !salt)
|
||||
if (!pk || pk->size > N_len(SRP_NG_3072)) // max 384 bytes
|
||||
{
|
||||
handle->errmsg = "Setup response 1: Missing or invalid pk/salt";
|
||||
handle->errmsg = "Setup response 1: Missing or invalid public key";
|
||||
goto error;
|
||||
}
|
||||
|
||||
sctx->pkB_len = pk->size; // 384
|
||||
salt = pair_tlv_get_value(response, TLVType_Salt);
|
||||
if (!salt || salt->size != 16)
|
||||
{
|
||||
handle->errmsg = "Setup response 1: Missing or invalid salt";
|
||||
goto error;
|
||||
}
|
||||
|
||||
sctx->pkB_len = pk->size;
|
||||
sctx->pkB = malloc(sctx->pkB_len);
|
||||
memcpy(sctx->pkB, pk->value, sctx->pkB_len);
|
||||
|
||||
sctx->salt_len = salt->size; // 16
|
||||
sctx->salt_len = salt->size;
|
||||
sctx->salt = malloc(sctx->salt_len);
|
||||
memcpy(sctx->salt, salt->value, sctx->salt_len);
|
||||
|
||||
@@ -1436,13 +1487,13 @@ client_setup_response2(struct pair_setup_context *handle, const uint8_t *data, s
|
||||
}
|
||||
|
||||
proof = pair_tlv_get_value(response, TLVType_Proof);
|
||||
if (!proof)
|
||||
if (!proof || proof->size != SHA512_DIGEST_LENGTH)
|
||||
{
|
||||
handle->errmsg = "Setup response 2: Missing proof";
|
||||
handle->errmsg = "Setup response 2: Missing or invalid proof";
|
||||
goto error;
|
||||
}
|
||||
|
||||
sctx->M2_len = proof->size; // 64
|
||||
sctx->M2_len = proof->size;
|
||||
sctx->M2 = malloc(sctx->M2_len);
|
||||
memcpy(sctx->M2, proof->value, sctx->M2_len);
|
||||
|
||||
@@ -2050,17 +2101,22 @@ server_setup_request2(struct pair_setup_context *handle, const uint8_t *data, si
|
||||
}
|
||||
|
||||
pk = pair_tlv_get_value(request, TLVType_PublicKey);
|
||||
proof = pair_tlv_get_value(request, TLVType_Proof);
|
||||
if (!pk || !proof)
|
||||
if (!pk || pk->size > N_len(SRP_NG_3072)) // 384 bytes or less
|
||||
{
|
||||
RETURN_ERROR(PAIR_STATUS_INVALID, "Setup request 2: Missing pkA or proof");
|
||||
RETURN_ERROR(PAIR_STATUS_INVALID, "Setup request 2: Missing og invalid public key");
|
||||
}
|
||||
|
||||
sctx->pkA_len = pk->size; // 384
|
||||
proof = pair_tlv_get_value(request, TLVType_Proof);
|
||||
if (!proof || proof->size != SHA512_DIGEST_LENGTH)
|
||||
{
|
||||
RETURN_ERROR(PAIR_STATUS_INVALID, "Setup request 2: Missing or invalid proof");
|
||||
}
|
||||
|
||||
sctx->pkA_len = pk->size;
|
||||
sctx->pkA = malloc(sctx->pkA_len);
|
||||
memcpy(sctx->pkA, pk->value, sctx->pkA_len);
|
||||
|
||||
sctx->M1_len = proof->size; // 64
|
||||
sctx->M1_len = proof->size;
|
||||
sctx->M1 = malloc(sctx->M1_len);
|
||||
memcpy(sctx->M1, proof->value, sctx->M1_len);
|
||||
|
||||
@@ -2072,7 +2128,7 @@ server_setup_request2(struct pair_setup_context *handle, const uint8_t *data, si
|
||||
goto out;
|
||||
}
|
||||
|
||||
sctx->M2_len = 64; // 512 bit hash
|
||||
sctx->M2_len = SHA512_DIGEST_LENGTH;
|
||||
srp_verifier_verify_session(sctx->verifier, sctx->M1, &sctx->M2);
|
||||
if (!sctx->M2)
|
||||
{
|
||||
|
||||
@@ -526,7 +526,7 @@ void release_hold_on_play_lock(__attribute__((unused)) rtsp_conn_info *conn) {
|
||||
}
|
||||
|
||||
void release_play_lock(rtsp_conn_info *conn) {
|
||||
debug(1, "Connection %d: release play lock.", conn->connection_number);
|
||||
debug(2, "Connection %d: release play lock.", conn->connection_number);
|
||||
debug_mutex_lock(&playing_conn_lock, 1000000, 3);
|
||||
if (playing_conn == conn) { // if we have the player
|
||||
playing_conn = NULL; // let it go
|
||||
@@ -536,7 +536,7 @@ void release_play_lock(rtsp_conn_info *conn) {
|
||||
}
|
||||
|
||||
int get_play_lock(rtsp_conn_info *conn) {
|
||||
debug(1, "Connection %d: request play lock.", conn->connection_number);
|
||||
debug(2, "Connection %d: request play lock.", conn->connection_number);
|
||||
// returns -1 if it failed, 0 if it succeeded and 1 if it succeeded but
|
||||
// interrupted an existing session
|
||||
int response = 0;
|
||||
@@ -592,16 +592,16 @@ int get_play_lock(rtsp_conn_info *conn) {
|
||||
}
|
||||
|
||||
if ((have_the_player == 1) && (interrupting_current_session == 1)) {
|
||||
debug(1, "Connection %d: Got player lock", conn->connection_number);
|
||||
debug(2, "Connection %d: Got player lock", conn->connection_number);
|
||||
response = 1;
|
||||
} else {
|
||||
debug(1, "Connection %d: failed to get player lock", conn->connection_number);
|
||||
debug(1, "Connection %d: failed to get player lock after waiting.", conn->connection_number);
|
||||
response = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if ((have_the_player) && (interrupting_current_session == 0)) {
|
||||
debug(1, "Connection %d: Got player lock.", conn->connection_number);
|
||||
if ((have_the_player == 1) && (interrupting_current_session == 0)) {
|
||||
debug(2, "Connection %d: Got player lock.", conn->connection_number);
|
||||
response = 0;
|
||||
}
|
||||
return response;
|
||||
|
||||
Reference in New Issue
Block a user