]> git.ipfire.org Git - thirdparty/shairport-sync.git/commitdiff
Add update to ejurgensen's pair_ap library. Thanks as always.
authorMike Brady <4265913+mikebrady@users.noreply.github.com>
Wed, 8 Dec 2021 11:59:09 +0000 (11:59 +0000)
committerMike Brady <4265913+mikebrady@users.noreply.github.com>
Wed, 8 Dec 2021 11:59:09 +0000 (11:59 +0000)
pair_ap/client-example.c
pair_ap/pair-internal.h
pair_ap/pair.c
pair_ap/pair.h
pair_ap/pair_fruit.c
pair_ap/pair_homekit.c
rtsp.c

index 1cb766bbe930d1c6ce484475c8b02b71a4309116..c5736ed5aaa1d1f3f2e4f512c9762ecf83a39cd6 100644 (file)
@@ -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);
 }
index f9d8fa66b64cb8503a90a117ccf9c3fb881c66ce..3de74daa1a12652aa22a2d07de0706e0fb84c8b4 100644 (file)
@@ -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
index 2b58bbe14f50c38c071f1cd6f4107cc8839a0ffd..e444ab5ba3e964345794042a1cdb825816004bbb 100644 (file)
@@ -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
 
 
index d3be0ca95066102fc29c9cf8740fc6aa3a12b2c7..35a5aeb85c204a3a0119ff414ab3c6089843f484 100644 (file)
@@ -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
 
index 3236faf56e0ffae629193453bb6b36f4d0d06800..86f23636e4bedc46584650c59e298afa421e538c 100644 (file)
@@ -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;
index 6540d42d0e80cf7aac3ced5faefb247bfb57a901..d08baca293332109353ec6b2dbcb7318cbb4eb2c 100644 (file)
@@ -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);
+  if (!pk || pk->size > N_len(SRP_NG_3072)) // max 384 bytes
+    {
+      handle->errmsg = "Setup response 1: Missing or invalid public key";
+      goto error;
+    }
+
   salt = pair_tlv_get_value(response, TLVType_Salt);
-  if (!pk || !salt)
+  if (!salt || salt->size != 16)
     {
-      handle->errmsg = "Setup response 1: Missing or invalid pk/salt";
+      handle->errmsg = "Setup response 1: Missing or invalid salt";
       goto error;
     }
 
-  sctx->pkB_len = pk->size; // 384
+  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);
+  if (!pk || pk->size > N_len(SRP_NG_3072)) // 384 bytes or less
+    {
+      RETURN_ERROR(PAIR_STATUS_INVALID, "Setup request 2: Missing og invalid public key");
+    }
+
   proof = pair_tlv_get_value(request, TLVType_Proof);
-  if (!pk || !proof)
+  if (!proof || proof->size != SHA512_DIGEST_LENGTH)
     {
-      RETURN_ERROR(PAIR_STATUS_INVALID, "Setup request 2: Missing pkA or proof");
+      RETURN_ERROR(PAIR_STATUS_INVALID, "Setup request 2: Missing or invalid proof");
     }
 
-  sctx->pkA_len = pk->size; // 384
+  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)
     {
diff --git a/rtsp.c b/rtsp.c
index e350b5a492f1be838cf8ef68d5dde26d43b71801..54f3b73aaad87b2c0b247991438caadd9f000a3d 100644 (file)
--- a/rtsp.c
+++ b/rtsp.c
@@ -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;