{"record":{"id":"506d186f194e9108","repo":"mgth/LittleBigMouse","slug":"the-c1-requires-the-vidaa-client-certificate-extract-the-p12-506d18","errorCode":null,"errorMessage":"The C1 requires the VIDAA client certificate. Extract the .p12 from the official Android APK and copy it to {DefaultPath}.","messagePattern":"The C1 requires the VIDAA client certificate\\. Extract the \\.p12 from the official Android APK and copy it to (.+?)\\.","errorType":"exception","errorClass":"System.Security.Authentication.AuthenticationException","httpStatus":null,"severity":"error","filePath":"LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/HisenseVidaa/VidaaMqttConnection.cs","lineNumber":83,"sourceCode":"            }, cancellationToken).ConfigureAwait(false);\n        }\n        catch (AuthenticationException e) when (certificates.Count == 0)\n        {\n            throw new AuthenticationException(\n                \"VIDAA rejected TLS. Select the PKCS#12 client certificate extracted from the official app.\", e);\n        }\n\n        _stream = ssl;\n        await WritePacketAsync(BuildConnectPacket(clientId, username, password), cancellationToken)\n            .ConfigureAwait(false);\n        (byte Header, byte[] Payload) connack;\n        try\n        {\n            connack = await ReadPacketAsync(_stream, cancellationToken).ConfigureAwait(false);\n        }\n        catch (IOException e) when (certificates.Count == 0)\n        {\n            throw VidaaCertificate.MissingException(e);\n        }\n        if ((connack.Header >> 4) != 2 || connack.Payload.Length < 2)\n            throw new IOException(\"VIDAA returned an invalid MQTT connection response.\");\n        if (connack.Payload[1] != 0)\n            throw new UnauthorizedAccessException(MqttError(connack.Payload[1]));\n\n        _connected = true;\n        // The caller token limits the handshake only. Once established, MQTT has\n        // its own lifetime so a completed UI command cannot tear down the session.\n        _lifetime = new CancellationTokenSource();\n        _readerTask = ReadLoopAsync(_lifetime.Token);\n        _pingTask = PingLoopAsync(_lifetime.Token);\n    }\n\n    public async Task SubscribeAsync(IEnumerable<string> topics, CancellationToken cancellationToken)\n    {\n        foreach (var topic in topics)\n        {","sourceCodeStart":65,"sourceCodeEnd":101,"githubUrl":"https://github.com/mgth/LittleBigMouse/blob/7a42f01d47d99d223b8ee33ba4019af82adf1c48/LittleBigMouse.Plugins/LittleBigMouse.Plugin.Vcp.Avalonia/HisenseVidaa/VidaaMqttConnection.cs#L65-L101","documentation":"During VIDAA MQTT ConnectAsync, the TCP read of the CONNACK packet can surface an IOException. The filter `when (certificates.Count == 0)` distinguishes a TLS handshake failure caused by an absent client certificate from other IO faults, and rethrows it as VidaaCertificate.MissingException(e). The message tells the user to extract the .p12 from the official Android APK and copy it to the default path.","triggerScenarios":"Calling ConnectAsync (via OpenMqttAsync) when the TLS client-hello carries no client certificate (certificates.Count == 0) and the device/stack aborts the handshake with an IOException — i.e. the .p12 was never loaded because it is missing at the configured path.","commonSituations":"Same as the pre-flight MissingException but detected later: certificate file deleted after configuration was saved; path points to an unreadable/empty file so no certificate loaded; container without the cert mounted; stale config after app reinstall.","solutions":["Extract the .p12 from the official Hisense Android APK and place it at the DefaultPath, then retry the connection.","Point ClientCertificatePath in HisenseVidaaConfiguration at the actual .p12 file and confirm File.Exists passes.","Check file permissions on the .p12 (must be readable by the daemon user).","Confirm the certificate loaded successfully before connecting (e.g. inspect certificates.Count / certificate load logs) to rule out a load-time failure rather than a missing file."],"exampleFix":"// before\nawait OpenMqttAsync(config, ct); // throws MissingException\n// after\nvar certPath = VidaaCertificate.Resolve(config.ClientCertificatePath);\nif (string.IsNullOrWhiteSpace(certPath) || !File.Exists(certPath))\n    throw new InvalidOperationException($\"Copy the extracted .p12 to {VidaaCertificate.DefaultPath} before connecting.\");","handlingStrategy":"try-catch","validationCode":"// before connecting\nvar certPath = VidaaCertificate.Resolve(config.ClientCertificatePath);\nif (string.IsNullOrWhiteSpace(certPath) || !File.Exists(certPath))\n    throw new InvalidOperationException($\"Copy the extracted .p12 to {VidaaCertificate.DefaultPath} before connecting.\");","typeGuard":null,"tryCatchPattern":"try { await connection.OpenMqttAsync(config, ct); }\ncatch (Exception e) when (e.Message.Contains(\"VIDAA client certificate\")) {\n    // cert absent -> surface setup instructions, do not retry blind\n    ui.PromptCertificateInstall(VidaaCertificate.DefaultPath);\n}","preventionTips":["Pre-validate the certificate file exists and loads (X509Certificate2 constructor) before every connection attempt.","Mount/copy the .p12 into containers and CI environments as part of environment provisioning.","Distinguish missing-cert IOException from other IO faults with a pre-flight load check rather than relying on the catch filter."],"tags":["mqtt","tls","client-certificate","hisense","vidaa"],"backgroundTag":"missing-credentials","analyzedSha":"7a42f01d47d99d223b8ee33ba4019af82adf1c48","analyzedAt":"2026-09-16T00:35:00.514Z","contentChangedAt":"2026-09-16T00:35:00.514Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}