Improve homekit tlv8 parsing

This commit is contained in:
Alex X
2025-10-21 12:26:24 +03:00
parent 7254bd4fbc
commit 994e0dc526
6 changed files with 43 additions and 21 deletions
+2 -2
View File
@@ -124,7 +124,7 @@ func (c *Client) Dial() (err error) {
EncryptedData string `tlv8:"5"`
State byte `tlv8:"6"`
}
if err = tlv8.UnmarshalReader(res.Body, &cipherM2); err != nil {
if err = tlv8.UnmarshalReader(res.Body, res.ContentLength, &cipherM2); err != nil {
return err
}
if cipherM2.State != StateM2 {
@@ -209,7 +209,7 @@ func (c *Client) Dial() (err error) {
var plainM4 struct {
State byte `tlv8:"6"`
}
if err = tlv8.UnmarshalReader(res.Body, &plainM4); err != nil {
if err = tlv8.UnmarshalReader(res.Body, res.ContentLength, &plainM4); err != nil {
return
}
if plainM4.State != StateM4 {
+6 -6
View File
@@ -107,7 +107,7 @@ func (c *Client) Pair(feature, pin string) (err error) {
State byte `tlv8:"6"`
Error byte `tlv8:"7"`
}
if err = tlv8.UnmarshalReader(res.Body, &plainM2); err != nil {
if err = tlv8.UnmarshalReader(res.Body, res.ContentLength, &plainM2); err != nil {
return
}
if plainM2.State != StateM2 {
@@ -159,7 +159,7 @@ func (c *Client) Pair(feature, pin string) (err error) {
EncryptedData string `tlv8:"5"` // skip EncryptedData validation (for MFi devices)
}
if err = tlv8.UnmarshalReader(res.Body, &plainM4); err != nil {
if err = tlv8.UnmarshalReader(res.Body, res.ContentLength, &plainM4); err != nil {
return
}
if plainM4.State != StateM4 {
@@ -232,7 +232,7 @@ func (c *Client) Pair(feature, pin string) (err error) {
State byte `tlv8:"6"`
Error byte `tlv8:"7"`
}{}
if err = tlv8.UnmarshalReader(res.Body, &cipherM6); err != nil {
if err = tlv8.UnmarshalReader(res.Body, res.ContentLength, &cipherM6); err != nil {
return
}
if cipherM6.State != StateM6 || cipherM6.Error != 0 {
@@ -296,7 +296,7 @@ func (c *Client) ListPairings() error {
State byte `tlv8:"6"`
Permission byte `tlv8:"11"`
}
if err = tlv8.UnmarshalReader(res.Body, &plainM2); err != nil {
if err = tlv8.UnmarshalReader(res.Body, res.ContentLength, &plainM2); err != nil {
return err
}
@@ -329,7 +329,7 @@ func (c *Client) PairingsAdd(clientID string, clientPublic []byte, admin bool) e
State byte `tlv8:"6"`
Unknown byte `tlv8:"7"`
}
if err = tlv8.UnmarshalReader(res.Body, &plainM2); err != nil {
if err = tlv8.UnmarshalReader(res.Body, res.ContentLength, &plainM2); err != nil {
return err
}
@@ -354,7 +354,7 @@ func (c *Client) DeletePairing(id string) error {
var plainM2 struct {
State byte `tlv8:"6"`
}
if err = tlv8.UnmarshalReader(res.Body, &plainM2); err != nil {
if err = tlv8.UnmarshalReader(res.Body, res.ContentLength, &plainM2); err != nil {
return err
}
if plainM2.State != StateM2 {
+2 -3
View File
@@ -6,7 +6,6 @@ import (
"encoding/base64"
"errors"
"fmt"
"io"
"net"
"net/http"
@@ -55,7 +54,7 @@ func (s *Server) PairVerify(req *http.Request, rw *bufio.ReadWriter, conn net.Co
PublicKey string `tlv8:"3"`
State byte `tlv8:"6"`
}
if err := tlv8.UnmarshalReader(io.LimitReader(rw, req.ContentLength), &plainM1); err != nil {
if err := tlv8.UnmarshalReader(req.Body, req.ContentLength, &plainM1); err != nil {
return err
}
if plainM1.State != StateM1 {
@@ -125,7 +124,7 @@ func (s *Server) PairVerify(req *http.Request, rw *bufio.ReadWriter, conn net.Co
EncryptedData string `tlv8:"5"`
State byte `tlv8:"6"`
}
if err = tlv8.UnmarshalReader(req.Body, &cipherM3); err != nil {
if err = tlv8.UnmarshalReader(req.Body, req.ContentLength, &cipherM3); err != nil {
return err
}
if cipherM3.State != StateM3 {
+21 -7
View File
@@ -5,7 +5,6 @@ import (
"crypto/sha512"
"errors"
"fmt"
"io"
"net"
"net/http"
@@ -25,18 +24,33 @@ const (
PairMethodList
)
func (s *Server) PairSetup(req *http.Request, rw *bufio.ReadWriter, conn net.Conn) error {
if req.Header.Get("Content-Type") != MimeTLV8 {
return errors.New("hap: wrong content type")
func (s *Server) HandleConn(conn net.Conn) error {
rd := bufio.NewReader(conn)
req, err := http.ReadRequest(rd)
if err != nil {
return err
}
rw := bufio.NewReadWriter(rd, bufio.NewWriter(conn))
switch req.RequestURI {
case PathPairSetup:
return s.PairSetup(req, rw, conn)
case PathPairVerify:
return s.PairVerify(req, rw, conn)
}
return errors.New("hap: unsupported request uri: " + req.RequestURI)
}
func (s *Server) PairSetup(req *http.Request, rw *bufio.ReadWriter, conn net.Conn) error {
// STEP 1. Request from iPhone
var plainM1 struct {
Method byte `tlv8:"0"`
State byte `tlv8:"6"`
Flags uint32 `tlv8:"19"`
}
if err := tlv8.UnmarshalReader(io.LimitReader(rw, req.ContentLength), &plainM1); err != nil {
if err := tlv8.UnmarshalReader(req.Body, req.ContentLength, &plainM1); err != nil {
return err
}
if plainM1.State != StateM1 {
@@ -87,7 +101,7 @@ func (s *Server) PairSetup(req *http.Request, rw *bufio.ReadWriter, conn net.Con
Proof string `tlv8:"4"`
State byte `tlv8:"6"`
}
if err = tlv8.UnmarshalReader(req.Body, &plainM3); err != nil {
if err = tlv8.UnmarshalReader(req.Body, req.ContentLength, &plainM3); err != nil {
return err
}
if plainM3.State != StateM3 {
@@ -129,7 +143,7 @@ func (s *Server) PairSetup(req *http.Request, rw *bufio.ReadWriter, conn net.Con
EncryptedData string `tlv8:"5"`
State byte `tlv8:"6"`
}
if err = tlv8.UnmarshalReader(req.Body, &cipherM5); err != nil {
if err = tlv8.UnmarshalReader(req.Body, req.ContentLength, &cipherM5); err != nil {
return err
}
if cipherM5.State != StateM5 {
+11 -2
View File
@@ -170,11 +170,20 @@ func UnmarshalBase64(in any, out any) error {
return Unmarshal(data, out)
}
func UnmarshalReader(r io.Reader, v any) error {
data, err := io.ReadAll(r)
func UnmarshalReader(r io.Reader, n int64, v any) error {
var data []byte
var err error
if n > 0 {
data = make([]byte, n)
_, err = io.ReadFull(r, data)
} else {
data, err = io.ReadAll(r)
}
if err != nil {
return err
}
return Unmarshal(data, v)
}
+1 -1
View File
@@ -139,7 +139,7 @@ func handlePairings(conn net.Conn, req *http.Request, pair ServerPair) (*http.Re
Permissions byte `tlv8:"11"`
}{}
if err := tlv8.UnmarshalReader(req.Body, &cmd); err != nil {
if err := tlv8.UnmarshalReader(req.Body, req.ContentLength, &cmd); err != nil {
return nil, err
}