validateCertificate method

Future<bool> validateCertificate({
  1. required String host,
  2. required List<String> pins,
  3. Duration timeout = const Duration(seconds: 10),
})

Implementation

Future<bool> validateCertificate({
  required String host,
  required List<String> pins,
  Duration timeout = const Duration(seconds: 10),
}) async {
  final client = HttpClient();
  client.connectionTimeout = timeout;
  // Allow self-signed / mismatched certs so we can inspect the certificate
  // ourselves; the actual security decision is made by the SPKI pin check.
  client.badCertificateCallback = (cert, h, port) => true;
  try {
    final request = await client.headUrl(Uri.https(host, '/'));
    final response = await request.close();

    final certificate = response.certificate;
    if (certificate == null) {
      await response.drain<void>();
      return false;
    }

    final spki = _extractSpki(Uint8List.fromList(certificate.der));
    if (spki == null) {
      await response.drain<void>();
      return false;
    }

    final fingerprint = base64.encode(sha256.convert(spki).bytes);
    final normalised = pins
        .map((p) => p.startsWith('sha256/') ? p.substring(7) : p)
        .toSet();

    await response.drain<void>();
    return normalised.contains(fingerprint);
  } finally {
    client.close();
  }
}