// Handle processes a container to pair with a new client without going through the pairing process. func (c *PairingController) Handle(cont util.Container) (util.Container, error) { method := pairMethodType(cont.GetByte(TagPairingMethod)) username := cont.GetString(TagUsername) publicKey := cont.GetBytes(TagPublicKey) log.Println("[VERB] -> Method:", method) log.Println("[VERB] -> Username:"******"[VERB] -> LTPK:", publicKey) entity := db.NewEntity(username, publicKey, nil) switch method { case PairingMethodDelete: log.Printf("[INFO] Remove LTPK for client '%s'\n", username) c.database.DeleteEntity(entity) case PairingMethodAdd: err := c.database.SaveEntity(entity) if err != nil { log.Println("[ERRO]", err) return nil, err } default: return nil, fmt.Errorf("Invalid pairing method type %v", method) } out := util.NewTLV8Container() out.SetByte(TagSequence, 0x2) return out, nil }
// Client -> Server // - encrypted tlv8: client LTPK, client name and signature (of H, client name, LTPK) // - auth tag (mac) // // Server // - Validate signature of encrpyted tlv8 // - Read and store client LTPK and name // // Server -> Client // - encrpyted tlv8: bridge LTPK, bridge name, signature (of hash `H2`, bridge name, LTPK) func (setup *SetupClientController) handleKeyExchange(in util.Container) (util.Container, error) { data := in.GetBytes(TagEncryptedData) message := data[:(len(data) - 16)] var mac [16]byte copy(mac[:], data[len(message):]) // 16 byte (MAC) fmt.Println("-> Message:", hex.EncodeToString(message)) fmt.Println("-> MAC:", hex.EncodeToString(mac[:])) decrypted, err := chacha20poly1305.DecryptAndVerify(setup.session.EncryptionKey[:], []byte("PS-Msg06"), message, mac, nil) if err != nil { fmt.Println(err) } else { decryptedBuf := bytes.NewBuffer(decrypted) in, err := util.NewTLV8ContainerFromReader(decryptedBuf) if err != nil { fmt.Println(err) } username := in.GetString(TagUsername) ltpk := in.GetBytes(TagPublicKey) signature := in.GetBytes(TagSignature) fmt.Println("-> Username:"******"-> LTPK:", hex.EncodeToString(ltpk)) fmt.Println("-> Signature:", hex.EncodeToString(signature)) entity := db.NewEntity(username, ltpk, nil) err = setup.database.SaveEntity(entity) if err != nil { fmt.Println("[ERRO]", err) } } return nil, err }
// Server -> Client // - only sequence number // - error code (optional) func (verify *VerifyServerController) handlePairVerifyFinish(in util.Container) (util.Container, error) { verify.step = VerifyStepFinishResponse data := in.GetBytes(TagEncryptedData) message := data[:(len(data) - 16)] var mac [16]byte copy(mac[:], data[len(message):]) // 16 byte (MAC) log.Debug.Println("-> Message:", hex.EncodeToString(message)) log.Debug.Println("-> MAC:", hex.EncodeToString(mac[:])) decryptedBytes, err := chacha20poly1305.DecryptAndVerify(verify.session.EncryptionKey[:], []byte("PV-Msg03"), message, mac, nil) out := util.NewTLV8Container() out.SetByte(TagSequence, verify.step.Byte()) if err != nil { verify.reset() log.Info.Panic(err) out.SetByte(TagErrCode, ErrCodeAuthenticationFailed.Byte()) // return error 2 } else { in, err := util.NewTLV8ContainerFromReader(bytes.NewBuffer(decryptedBytes)) if err != nil { return nil, err } username := in.GetString(TagUsername) signature := in.GetBytes(TagSignature) log.Debug.Println(" client:", username) log.Debug.Println(" signature:", hex.EncodeToString(signature)) entity, err := verify.database.EntityWithName(username) if err != nil { return nil, fmt.Errorf("Client %s is unknown", username) } if len(entity.PublicKey) == 0 { return nil, fmt.Errorf("No LTPK available for client %s", username) } var material []byte material = append(material, verify.session.OtherPublicKey[:]...) material = append(material, []byte(username)...) material = append(material, verify.session.PublicKey[:]...) if crypto.ValidateED25519Signature(entity.PublicKey, material, signature) == false { log.Debug.Println("signature is invalid") verify.reset() out.SetByte(TagErrCode, ErrCodeUnknownPeer.Byte()) // return error 4 } else { log.Debug.Println("signature is valid") } } return out, nil }
// Client -> Server // - encrypted tlv8: entity ltpk, entity name and signature (of H, entity name, ltpk) // - auth tag (mac) // // Server // - Validate signature of encrpyted tlv8 // - Read and store entity ltpk and name // // Server -> Client // - encrpyted tlv8: bridge ltpk, bridge name, signature (of hash, bridge name, ltpk) func (setup *SetupServerController) handleKeyExchange(in util.Container) (util.Container, error) { out := util.NewTLV8Container() setup.step = PairStepKeyExchangeResponse out.SetByte(TagSequence, setup.step.Byte()) data := in.GetBytes(TagEncryptedData) message := data[:(len(data) - 16)] var mac [16]byte copy(mac[:], data[len(message):]) // 16 byte (MAC) log.Debug.Println("-> Message:", hex.EncodeToString(message)) log.Debug.Println("-> MAC:", hex.EncodeToString(mac[:])) decrypted, err := chacha20poly1305.DecryptAndVerify(setup.session.EncryptionKey[:], []byte("PS-Msg05"), message, mac, nil) if err != nil { setup.reset() log.Info.Panic(err) out.SetByte(TagErrCode, ErrCodeUnknown.Byte()) // return error 1 } else { decryptedBuf := bytes.NewBuffer(decrypted) in, err := util.NewTLV8ContainerFromReader(decryptedBuf) if err != nil { return nil, err } username := in.GetString(TagUsername) clientltpk := in.GetBytes(TagPublicKey) signature := in.GetBytes(TagSignature) log.Debug.Println("-> Username:"******"-> ltpk:", hex.EncodeToString(clientltpk)) log.Debug.Println("-> Signature:", hex.EncodeToString(signature)) // Calculate hash `H` hash, _ := hkdf.Sha512(setup.session.PrivateKey, []byte("Pair-Setup-Controller-Sign-Salt"), []byte("Pair-Setup-Controller-Sign-Info")) var material []byte material = append(material, hash[:]...) material = append(material, []byte(username)...) material = append(material, clientltpk...) if crypto.ValidateED25519Signature(clientltpk, material, signature) == false { log.Debug.Println("ed25519 signature is invalid") setup.reset() out.SetByte(TagErrCode, ErrCodeAuthenticationFailed.Byte()) // return error 2 } else { log.Debug.Println("ed25519 signature is valid") // Store entity ltpk and name entity := db.NewEntity(username, clientltpk, nil) setup.database.SaveEntity(entity) log.Debug.Printf("Stored ltpk '%s' for entity '%s'\n", hex.EncodeToString(clientltpk), username) ltpk := setup.device.PublicKey() ltsk := setup.device.PrivateKey() // Send username, ltpk, signature as encrypted message hash, err := hkdf.Sha512(setup.session.PrivateKey, []byte("Pair-Setup-Accessory-Sign-Salt"), []byte("Pair-Setup-Accessory-Sign-Info")) material = make([]byte, 0) material = append(material, hash[:]...) material = append(material, []byte(setup.session.Username)...) material = append(material, ltpk...) signature, err := crypto.ED25519Signature(ltsk, material) if err != nil { log.Info.Panic(err) return nil, err } tlvPairKeyExchange := util.NewTLV8Container() tlvPairKeyExchange.SetBytes(TagUsername, setup.session.Username) tlvPairKeyExchange.SetBytes(TagPublicKey, ltpk) tlvPairKeyExchange.SetBytes(TagSignature, []byte(signature)) log.Debug.Println("<- Username:"******"<- ltpk:", hex.EncodeToString(tlvPairKeyExchange.GetBytes(TagPublicKey))) log.Debug.Println("<- Signature:", hex.EncodeToString(tlvPairKeyExchange.GetBytes(TagSignature))) encrypted, mac, _ := chacha20poly1305.EncryptAndSeal(setup.session.EncryptionKey[:], []byte("PS-Msg06"), tlvPairKeyExchange.BytesBuffer().Bytes(), nil) out.SetByte(TagSequence, PairStepKeyExchangeRequest.Byte()) out.SetBytes(TagEncryptedData, append(encrypted, mac[:]...)) } } return out, nil }