code.pfad.fr/gohmekit@v0.2.1/pairing/pair_setup.go (about) 1 package pairing 2 3 import ( 4 "crypto/ed25519" 5 "errors" 6 "fmt" 7 "io" 8 9 "code.pfad.fr/gohmekit/tlv8" 10 ) 11 12 type pairSetupRequest struct { 13 ktlvState 14 Method byte `tlv8:"kTLVType_Method"` 15 16 Identifier []byte `tlv8:"kTLVType_Identifier"` 17 PublicKey []byte `tlv8:"kTLVType_PublicKey"` 18 Proof []byte `tlv8:"kTLVType_Proof"` 19 EncryptedData []byte `tlv8:"kTLVType_EncryptedData"` 20 } 21 22 func (srv *HTTPServer) pairSetup(conn *encryptableConn, r io.Reader) ([]byte, error) { 23 var req pairSetupRequest 24 err := tlv8.NewDecoder(r).Decode(&req) 25 if err != nil { 26 return nil, err 27 } 28 29 switch req.State { 30 case 1: 31 return srv.pairSetupStartResponse(conn, req) 32 case 3: 33 return srv.pairSetupVerifyResponse(conn, req) 34 case 5: 35 return srv.pairSetupExchangeResponse(conn, req) 36 default: 37 return nil, fmt.Errorf("unexpected state: %d", req.State) 38 } 39 } 40 41 func (srv *HTTPServer) pairSetupStartResponse(conn *encryptableConn, req pairSetupRequest) ([]byte, error) { 42 if req.Method != kTLVMethod_PairSetup { 43 return nil, fmt.Errorf("unsupported method: %d", req.Method) 44 } 45 46 if srv.Database.IsPaired() { 47 return ktlvError(2, kTLVError_Unavailable) 48 } 49 50 session, salt, err := srv.Device.SRPSession() 51 if err != nil { 52 return nil, err 53 } 54 55 conn.pairSetup.SRPSession = session 56 conn.pairSetup.SRPSharedSecret = nil 57 58 return tlv8.Marshal(struct { 59 ktlvState 60 Salt []byte `tlv8:"kTLVType_Salt"` 61 PublicKey []byte `tlv8:"kTLVType_PublicKey"` 62 }{ 63 ktlvState: ktlvState{2}, 64 PublicKey: session.PublicKey(), 65 Salt: salt, 66 }) 67 } 68 69 func (srv *HTTPServer) pairSetupVerifyResponse(conn *encryptableConn, req pairSetupRequest) ([]byte, error) { 70 if conn.pairSetup.SRPSession == nil { 71 return nil, errors.New("shared secret has not been constructed yet") 72 } 73 74 iOSPublicKey := req.PublicKey 75 sessionKey, err := conn.pairSetup.SRPSession.PairSetupSharedSecret(iOSPublicKey) 76 if err != nil { 77 return nil, err 78 } 79 80 clientProof := req.Proof 81 serverProof, ok := conn.pairSetup.SRPSession.ExchangeProof(clientProof) 82 if !ok { 83 return ktlvError(4, kTLVError_Authentication) 84 } 85 86 conn.pairSetup.SRPSharedSecret = sessionKey 87 88 return tlv8.Marshal(struct { 89 ktlvState 90 Proof []byte `tlv8:"kTLVType_Proof"` 91 }{ 92 ktlvState: ktlvState{4}, 93 Proof: serverProof, 94 }) 95 } 96 97 func (srv *HTTPServer) pairSetupExchangeResponse(conn *encryptableConn, req pairSetupRequest) ([]byte, error) { 98 if len(conn.pairSetup.SRPSharedSecret) == 0 { 99 return nil, errors.New("session key has not been constructed yet") 100 } 101 102 aead, err := conn.pairSetup.SRPSharedSecret.AEAD() 103 if err != nil { 104 return nil, err 105 } 106 107 encryptedData := req.EncryptedData 108 decryptedData, err := aead.Open(encryptedData[:0], paddedNonce("PS-Msg05"), encryptedData, nil) 109 if err != nil { 110 return ktlvError(6, kTLVError_Authentication) 111 } 112 113 type subTLV struct { 114 Identifier []byte `tlv8:"kTLVType_Identifier"` 115 PublicKey []byte `tlv8:"kTLVType_PublicKey"` 116 Signature []byte `tlv8:"kTLVType_Signature"` 117 } 118 var decodedData subTLV 119 err = tlv8.Unmarshal(decryptedData, &decodedData) 120 if err != nil { 121 return nil, fmt.Errorf("could not decode encrypted data: %w", err) 122 } 123 124 iOSDevicePairingID := decodedData.Identifier 125 iOSDeviceLTPK := decodedData.PublicKey 126 iOSDeviceSignature := decodedData.Signature 127 128 hash, err := conn.pairSetup.SRPSharedSecret.ControllerSign() 129 if err != nil { 130 return nil, fmt.Errorf("could not decode encrypted data: %w", err) 131 } 132 133 var iOSDeviceInfo []byte 134 iOSDeviceInfo = append(iOSDeviceInfo, hash...) 135 iOSDeviceInfo = append(iOSDeviceInfo, iOSDevicePairingID...) 136 iOSDeviceInfo = append(iOSDeviceInfo, iOSDeviceLTPK...) 137 138 if !ed25519.Verify(iOSDeviceLTPK, iOSDeviceInfo, iOSDeviceSignature) { 139 return ktlvError(6, kTLVError_Authentication) 140 } 141 142 err = srv.Database.AddLongTermPublicKey(Controller{PairingID: iOSDevicePairingID, LongTermPublicKey: iOSDeviceLTPK}) 143 if err != nil { 144 return nil, fmt.Errorf("could not decode encrypted data: %w", err) 145 } 146 147 hash, err = conn.pairSetup.SRPSharedSecret.AccessorySign() 148 if err != nil { 149 return nil, fmt.Errorf("could not decode encrypted data: %w", err) 150 } 151 152 var accessoryInfo []byte 153 accessoryInfo = append(accessoryInfo, hash...) 154 accessoryInfo = append(accessoryInfo, srv.Device.PairingID()...) 155 accessoryInfo = append(accessoryInfo, srv.Device.OwnLongTermPublicKey()...) 156 157 accessorySignature, err := srv.Device.Ed25519Sign(accessoryInfo) 158 if err != nil { 159 return nil, fmt.Errorf("could not decode encrypted data: %w", err) 160 } 161 162 cleartextData, err := tlv8.Marshal(subTLV{ 163 Identifier: srv.Device.PairingID(), 164 PublicKey: srv.Device.OwnLongTermPublicKey(), 165 Signature: accessorySignature, 166 }) 167 if err != nil { 168 return nil, err 169 } 170 171 encryptedData = aead.Seal(cleartextData[:0], paddedNonce("PS-Msg06"), cleartextData, nil) 172 173 conn.pairSetup.SRPSession = nil 174 conn.pairSetup.SRPSharedSecret = nil 175 176 srv.Logger.Log("completed", "pair-setup", "id", string(iOSDevicePairingID)) 177 178 return tlv8.Marshal(struct { 179 ktlvState 180 EncryptedData []byte `tlv8:"kTLVType_EncryptedData"` 181 }{ 182 ktlvState: ktlvState{6}, 183 EncryptedData: encryptedData, 184 }) 185 }