spki_hash_pinning

SPKI hash certificate pinning for Dart and Flutter.

Use this package when you want to verify that a server's public key hash matches a pinned allowlist before you send real traffic.

This package lets you:

  • probe a TLS endpoint and compute the server's SPKI SHA-256 hash
  • compare that hash against an allowlist
  • create an HttpClient that only accepts certificates whose SPKI hash matches your pins
  • open the example/ Flutter app and see package:http wired up against the pinned client
  • watch the demo logs while the fingerprint probe, pin check, and pinned request run

Install

dependencies:
  spki_hash_pinning: ^0.1.0

Example

import 'dart:io';

import 'package:spki_hash_pinning/spki_hash_pinning.dart';

Future<void> main() async {
  const pins = <String>[
    'iIXchKltI/LhgfClWR6ZRZhZdovNWnLq9AZqGfTX+QA=',
  ];

  final secure = await SpkiHashPinning.check(
    serverUrl: 'https://example.com',
    allowedFingerprints: pins,
  );

  if (!secure) {
    throw StateError('Pinned server fingerprint did not match');
  }

  final client = SpkiHashPinning.createHttpClient(
    allowedFingerprints: pins,
  );

  final request = await client.getUrl(Uri.parse('https://example.com'));
  final response = await request.close();
  print(response.statusCode);
  client.close(force: true);
}

Fingerprint formats

Pins can be supplied as:

  • Base64 SHA-256 digest
  • hex SHA-256 digest, with or without : separators
  • sha256/<base64> format

Release Notes

See CHANGELOG.md for version history.

Example app

The example/ app shows a minimal Flutter UI that:

  1. fetches the server's SPKI fingerprint
  2. copies that fingerprint into the pin field
  3. performs a request through package:http using the pinned HttpClient

The example includes Android, iOS, macOS, Windows, and web runners. The web runner shows a demo-only notice because live SPKI pinning depends on dart:io.

Troubleshooting

  • If a request fails on Android, make sure the runner has android.permission.INTERNET.
  • If a request fails on macOS, make sure the runner has the com.apple.security.network.client entitlement.
  • If pinning passes but the request still fails, check the demo logs for the observed server fingerprint and TLS error.
  • If you run the web example, it stays in demo mode because live SPKI pinning is not available in browsers.

Run it with:

cd example
flutter pub get
flutter run

Libraries

spki_hash_pinning