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"` EncryptedData string `tlv8:"5"`
State byte `tlv8:"6"` 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 return err
} }
if cipherM2.State != StateM2 { if cipherM2.State != StateM2 {
@@ -209,7 +209,7 @@ func (c *Client) Dial() (err error) {
var plainM4 struct { var plainM4 struct {
State byte `tlv8:"6"` 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 return
} }
if plainM4.State != StateM4 { 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"` State byte `tlv8:"6"`
Error byte `tlv8:"7"` 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 return
} }
if plainM2.State != StateM2 { 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) 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 return
} }
if plainM4.State != StateM4 { if plainM4.State != StateM4 {
@@ -232,7 +232,7 @@ func (c *Client) Pair(feature, pin string) (err error) {
State byte `tlv8:"6"` State byte `tlv8:"6"`
Error byte `tlv8:"7"` 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 return
} }
if cipherM6.State != StateM6 || cipherM6.Error != 0 { if cipherM6.State != StateM6 || cipherM6.Error != 0 {
@@ -296,7 +296,7 @@ func (c *Client) ListPairings() error {
State byte `tlv8:"6"` State byte `tlv8:"6"`
Permission byte `tlv8:"11"` 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 return err
} }
@@ -329,7 +329,7 @@ func (c *Client) PairingsAdd(clientID string, clientPublic []byte, admin bool) e
State byte `tlv8:"6"` State byte `tlv8:"6"`
Unknown byte `tlv8:"7"` 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 return err
} }
@@ -354,7 +354,7 @@ func (c *Client) DeletePairing(id string) error {
var plainM2 struct { var plainM2 struct {
State byte `tlv8:"6"` 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 return err
} }
if plainM2.State != StateM2 { if plainM2.State != StateM2 {
+2 -3
View File
@@ -6,7 +6,6 @@ import (
"encoding/base64" "encoding/base64"
"errors" "errors"
"fmt" "fmt"
"io"
"net" "net"
"net/http" "net/http"
@@ -55,7 +54,7 @@ func (s *Server) PairVerify(req *http.Request, rw *bufio.ReadWriter, conn net.Co
PublicKey string `tlv8:"3"` PublicKey string `tlv8:"3"`
State byte `tlv8:"6"` 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 return err
} }
if plainM1.State != StateM1 { 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"` EncryptedData string `tlv8:"5"`
State byte `tlv8:"6"` 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 return err
} }
if cipherM3.State != StateM3 { if cipherM3.State != StateM3 {
+21 -7
View File
@@ -5,7 +5,6 @@ import (
"crypto/sha512" "crypto/sha512"
"errors" "errors"
"fmt" "fmt"
"io"
"net" "net"
"net/http" "net/http"
@@ -25,18 +24,33 @@ const (
PairMethodList PairMethodList
) )
func (s *Server) PairSetup(req *http.Request, rw *bufio.ReadWriter, conn net.Conn) error { func (s *Server) HandleConn(conn net.Conn) error {
if req.Header.Get("Content-Type") != MimeTLV8 { rd := bufio.NewReader(conn)
return errors.New("hap: wrong content type") 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 // STEP 1. Request from iPhone
var plainM1 struct { var plainM1 struct {
Method byte `tlv8:"0"` Method byte `tlv8:"0"`
State byte `tlv8:"6"` State byte `tlv8:"6"`
Flags uint32 `tlv8:"19"` 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 return err
} }
if plainM1.State != StateM1 { 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"` Proof string `tlv8:"4"`
State byte `tlv8:"6"` 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 return err
} }
if plainM3.State != StateM3 { 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"` EncryptedData string `tlv8:"5"`
State byte `tlv8:"6"` 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 return err
} }
if cipherM5.State != StateM5 { if cipherM5.State != StateM5 {
+11 -2
View File
@@ -170,11 +170,20 @@ func UnmarshalBase64(in any, out any) error {
return Unmarshal(data, out) return Unmarshal(data, out)
} }
func UnmarshalReader(r io.Reader, v any) error { func UnmarshalReader(r io.Reader, n int64, v any) error {
data, err := io.ReadAll(r) 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 { if err != nil {
return err return err
} }
return Unmarshal(data, v) 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"` 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 return nil, err
} }