code.pfad.fr/gohmekit@v0.2.1/pairing/pair_verify.go (about) 1 package pairing 2 3 import ( 4 "crypto/ed25519" 5 "errors" 6 "fmt" 7 "io" 8 9 "code.pfad.fr/gohmekit/pairing/crypto" 10 "code.pfad.fr/gohmekit/tlv8" 11 ) 12 13 type pairVerifyRequest struct { 14 ktlvState 15 16 PublicKey []byte `tlv8:"kTLVType_PublicKey"` 17 EncryptedData []byte `tlv8:"kTLVType_EncryptedData"` 18 } 19 20 func (srv *HTTPServer) pairVerify(conn *encryptableConn, r io.Reader) ([]byte, error) { 21 var req pairVerifyRequest 22 err := tlv8.NewDecoder(r).Decode(&req) 23 if err != nil { 24 return nil, err 25 } 26 27 switch req.State { 28 case 1: 29 return srv.pairVerifyStartResponse(conn, req) 30 case 3: 31 return srv.pairVerifyFinishResponse(conn, req) 32 default: 33 return nil, fmt.Errorf("unexpected state: %d", req.State) 34 } 35 } 36 37 func (srv *HTTPServer) pairVerifyStartResponse(conn *encryptableConn, req pairVerifyRequest) ([]byte, error) { 38 key, err := crypto.NewKeyOnCurve25519() 39 if err != nil { 40 return nil, err 41 } 42 43 conn.pairVerify.ownPublicKey = key.PublicKey() 44 conn.pairVerify.iOSDevicePublicKey = req.PublicKey 45 46 conn.pairVerify.SharedSecret, err = key.PairVerifySharedSecret(conn.pairVerify.iOSDevicePublicKey) 47 if err != nil { 48 return nil, err 49 } 50 51 var accessoryInfo []byte 52 accessoryInfo = append(accessoryInfo, key.PublicKey()...) 53 accessoryInfo = append(accessoryInfo, srv.Device.PairingID()...) 54 accessoryInfo = append(accessoryInfo, conn.pairVerify.iOSDevicePublicKey...) 55 56 accessorySignature, err := srv.Device.Ed25519Sign(accessoryInfo) 57 if err != nil { 58 return nil, err 59 } 60 61 cleartextData, err := tlv8.Marshal(struct { 62 Identifier []byte `tlv8:"kTLVType_Identifier"` 63 Signature []byte `tlv8:"kTLVType_Signature"` 64 }{ 65 Identifier: srv.Device.PairingID(), 66 Signature: accessorySignature, 67 }) 68 if err != nil { 69 return nil, err 70 } 71 72 aead, err := crypto.PairVerifyAEAD(conn.pairVerify.SharedSecret) 73 if err != nil { 74 return nil, err 75 } 76 77 encryptedData := aead.Seal(cleartextData[:0], paddedNonce("PV-Msg02"), cleartextData, nil) 78 79 return tlv8.Marshal(struct { 80 ktlvState 81 PublicKey []byte `tlv8:"kTLVType_PublicKey"` 82 EncryptedData []byte `tlv8:"kTLVType_EncryptedData"` 83 }{ 84 ktlvState: ktlvState{2}, 85 PublicKey: key.PublicKey(), 86 EncryptedData: encryptedData, 87 }) 88 } 89 90 func (srv *HTTPServer) pairVerifyFinishResponse(conn *encryptableConn, req pairVerifyRequest) ([]byte, error) { 91 if len(conn.pairVerify.SharedSecret) == 0 { 92 return nil, errors.New("shared secret has not been constructed yet") 93 } 94 95 aead, err := crypto.PairVerifyAEAD(conn.pairVerify.SharedSecret) 96 if err != nil { 97 return nil, err 98 } 99 100 encryptedData := req.EncryptedData 101 decryptedData, err := aead.Open(encryptedData[:0], paddedNonce("PV-Msg03"), encryptedData, nil) 102 if err != nil { 103 return ktlvError(4, kTLVError_Authentication) 104 } 105 106 var decodedData struct { 107 Identifier []byte `tlv8:"kTLVType_Identifier"` 108 Signature []byte `tlv8:"kTLVType_Signature"` 109 } 110 err = tlv8.Unmarshal(decryptedData, &decodedData) 111 if err != nil { 112 return nil, fmt.Errorf("could not decode encrypted data: %w", err) 113 } 114 115 iOSDevicePairingID := decodedData.Identifier 116 iOSDeviceSignature := decodedData.Signature 117 118 iOSDeviceLTPK, err := srv.Database.GetLongTermPublicKey(iOSDevicePairingID) 119 if err != nil { 120 return nil, err 121 } 122 123 var iOSDeviceInfo []byte 124 iOSDeviceInfo = append(iOSDeviceInfo, conn.pairVerify.iOSDevicePublicKey...) 125 iOSDeviceInfo = append(iOSDeviceInfo, iOSDevicePairingID...) 126 iOSDeviceInfo = append(iOSDeviceInfo, conn.pairVerify.ownPublicKey...) 127 128 if !ed25519.Verify(iOSDeviceLTPK, iOSDeviceInfo, iOSDeviceSignature) { 129 return ktlvError(4, kTLVError_Authentication) 130 } 131 132 var sharedKey [32]byte 133 copy(sharedKey[:], conn.pairVerify.SharedSecret) 134 135 conn.pairVerify.ownPublicKey = nil 136 conn.pairVerify.iOSDevicePublicKey = nil 137 conn.pairVerify.SharedSecret = nil 138 139 srv.Logger.Log("completed", "pair-verify", "id", string(iOSDevicePairingID)) 140 141 err = conn.StartEncryptedSession(sharedKey, true) 142 if err != nil { 143 return nil, err 144 } 145 return tlv8.Marshal(ktlvState{4}) 146 }