smart_dev_pinning_plugin 3.1.0 copy "smart_dev_pinning_plugin: ^3.1.0" to clipboard
smart_dev_pinning_plugin: ^3.1.0 copied to clipboard

This plugin creates a secure native TLS connection to execute HTTP requests with certificate pinning.

Smart Dev Pinning Plugin #

A high-performance Flutter plugin that provides secure native TLS connections for HTTP requests with advanced SSL certificate pinning capabilities. Supports Leaf and Intermediate CA pinning in both public key and certificate hash modes, with non-blocking asynchronous FFI implementation.

Features #

  • 🔐 4 Pinning Methods: Leaf Certificate, Leaf Public Key, Intermediate Certificate, Intermediate Public Key
  • 🚀 High Performance: Native FFI implementation with asynchronous execution.
  • 🎯 Non-blocking UI: Isolate-based FFI execution prevents UI freezing on Android
  • 📊 Built-in Benchmarking: Comprehensive performance analysis tools
  • 🛡️ Type-safe API: Enum-based pinning method selection for enhanced safety
  • 📱 Cross-platform: Full Android and iOS support
  • Zero Dependencies: Minimal external dependencies for maximum compatibility

Key Improvements #

  • Asynchronous FFI: To execute FFI operations in separate Isolates
  • Enhanced Performance: Non-blocking operations ensure responsive UI during network requests
  • Consistent Behavior: Uniform asynchronous behavior across Android and iOS platforms
  • Modern Architecture: Improved native integration with (Android) and Swift (iOS)

Requirements #

  • Flutter 3.3.0 or higher
  • Dart SDK 3.3.0 or higher
  • Android API level 21+ (Android 5.0+)
  • iOS 11.0+

Installation #

Add the dependency to your pubspec.yaml:

dependencies:
  smart_dev_pinning_plugin: ^2.6.0

Then run:

flutter pub get

Usage Guide #

SSL Pinning Methods #

This plugin provides four certificate pinning strategies:

Leaf Pinning

  1. Public Key Pinning (PinningMethod.publicKey):

    • Pins against the server's (Leaf) public key
    • Survives certificate renewals if the key is reused
    • Recommended for services you control
  2. Leaf Certificate Pinning (PinningMethod.certificate):

    • Pins against the complete Leaf certificate DER hash
    • Strictest validation — breaks on any renewal
    • Best for maximum security on services you control

Intermediate CA Pinning

  1. Intermediate Public Key Pinning (PinningMethod.intermediatePublicKey):

    • Pins against the Intermediate CA's public key
    • Most stable option: survives Leaf rotations and CA renewals that keep the same key
    • Recommended for services behind CDN/WAF (Imperva, Cloudflare, Akamai)
  2. Intermediate Certificate Pinning (PinningMethod.intermediateCertificate):

    • Pins against the complete Intermediate CA certificate DER hash
    • More restrictive than Intermediate Public Key
    • Useful when you need to ensure a specific Intermediate CA is in the chain

Certificate Hash Generation #

Choose the appropriate method based on your pinning strategy:

Caution

Always use the bare domain with port (e.g., example.com:443) in the openssl s_client -connect command. Do NOT include https:// — using https://example.com:443 will resolve to a different host or fail silently, producing a hash that will not match what Rust/rustls computes at runtime.

Leaf Public Key Hash

openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null \
  | openssl x509 -pubkey -noout \
  | openssl pkey -pubin -outform DER \
  | openssl dgst -sha256 -binary \
  | openssl base64

Leaf Certificate Hash

openssl s_client -connect example.com:443 -servername example.com 2>/dev/null \
  | openssl x509 -outform DER \
  | openssl dgst -sha256 -binary \
  | openssl base64

Intermediate CA Public Key Hash

Use the -showcerts flag and extract the second certificate (index 1) in the chain:

# Save all certs in the chain
openssl s_client -showcerts -connect jsonplaceholder.typicode.com:443 -servername jsonplaceholder.typicode.com </dev/null 2>/dev/null \
  | awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{ if(/BEGIN/){n++}; if(n==2) print }' \
  | openssl x509 -pubkey -noout \
  | openssl pkey -pubin -outform DER \
  | openssl dgst -sha256 -binary \
  | openssl base64

Intermediate CA Certificate Hash

openssl s_client -showcerts -connect jsonplaceholder.typicode.com:443 -servername jsonplaceholder.typicode.com </dev/null 2>/dev/null \
  | awk '/BEGIN CERTIFICATE/,/END CERTIFICATE/{ if(/BEGIN/){n++}; if(n==2) print }' \
  | openssl x509 -outform DER \
  | openssl dgst -sha256 -binary \
  | openssl base64

Basic Implementation #

import 'package:smart_dev_pinning_plugin/smart_dev_pinning_plugin.dart';

final client = SecureClient();

// Public Key Pinning (Leaf)
final response = await client.httpRequest(
  certificateHash: "/UzJAZYxLBnEpBwXAcmd4WHi7f8aYgfMExGnoyp5B04=",
  method: 'GET',
  url: 'https://jsonplaceholder.typicode.com/posts/1',
  headers: {'Content-Type': 'application/json; charset=UTF-8'},
  pinningMethod: PinningMethod.publicKey,
);

if (response.success) {
  print('Data: ${response.data}');
} else {
  print('Error [${response.errorType}]: ${response.error}');
}

// Intermediate Public Key Pinning (Recommended for CDN/WAF services)
final cdnResponse = await client.httpRequest(
  certificateHash: "INTERMEDIATE_CA_PUBKEY_HASH_HERE",
  method: 'GET',
  url: 'https://cdn-backed-service.example.com/api',
  headers: {'Content-Type': 'application/json'},
  pinningMethod: PinningMethod.intermediatePublicKey,
);

if (cdnResponse.success) {
  print('CDN response: ${cdnResponse.data}');
} else {
  print('Error [${cdnResponse.errorType}]: ${cdnResponse.error}');
}

// Certificate Pinning (Leaf) with POST
final postResponse = await client.httpRequest(
  certificateHash: "YOUR_CERTIFICATE_HASH_HERE",
  method: 'POST',
  url: 'https://api.example.com/data',
  headers: {
    'Content-Type': 'application/json',
    'Authorization': 'Bearer your_token_here'
  },
  body: {'key': 'value'},
  pinningMethod: PinningMethod.certificate,
);

if (postResponse.success) {
  print('POST response: ${postResponse.data}');
} else {
  print('Error [${postResponse.errorType}]: ${postResponse.error}');
}

Advanced Usage Examples #

Handling Different Request Types

final client = SecureClient();

// GET request with query parameters
final getResponse = await client.httpRequest(
  certificateHash: "your_hash_here",
  method: 'GET',
  url: 'https://api.example.com/users?page=1&limit=10',
  headers: {'Accept': 'application/json'},
  pinningMethod: PinningMethod.publicKey,
);

// POST with JSON body
final postResponse = await client.httpRequest(
  certificateHash: "your_hash_here",
  method: 'POST',
  url: 'https://api.example.com/users',
  headers: {'Content-Type': 'application/json'},
  body: {
    'name': 'John Doe',
    'email': 'john@example.com'
  },
  pinningMethod: PinningMethod.publicKey,
);

// PUT with string body
final putResponse = await client.httpRequest(
  certificateHash: "your_hash_here",
  method: 'PUT',
  url: 'https://api.example.com/users/123',
  headers: {'Content-Type': 'text/plain'},
  body: 'Updated user data',
  pinningMethod: PinningMethod.publicKey,
);

Performance Benchmarking #

The plugin includes comprehensive benchmarking tools to analyze the performance impact of SSL pinning:

// The example app provides detailed performance analysis including:
// - Response time comparisons (Standard HTTP vs SSL Pinned requests)
// - Throughput measurements and statistical analysis
// - Visual performance metrics with charts and graphs
// - Memory usage and CPU impact assessment
// - Network latency analysis with SSL pinning overhead

Error Handling #

The plugin returns a SmartResponse object that encapsulates both success and error states — SSL pinning failures are not thrown as exceptions, they are returned in the response:

final response = await client.httpRequest(
  certificateHash: "invalid_hash",
  method: 'GET',
  url: 'https://example.com/api',
  headers: {},
  pinningMethod: PinningMethod.publicKey,
);

if (response.success) {
  print('Data: ${response.data}');
  print('Status code: ${response.statusCode}');
} else {
  // Check the errorType to determine the cause
  switch (response.errorType) {
    case 'ConnectionError':
      // SSL pinning mismatch, timeout, or connection failure
      print('Connection failed: ${response.error}');
      break;
    case 'SSLPinningError':
      // Client could not be created with the given hash
      print('SSL pinning setup error: ${response.error}');
      break;
    case 'HttpError':
      // Server returned a non-2xx status code
      print('HTTP ${response.statusCode}: ${response.error}');
      break;
    case 'RequestError':
      // Other request-level failures
      print('Request error: ${response.error}');
      break;
    default:
      print('Unknown error: ${response.error}');
  }
}

Error Types Reference

errorType When it occurs
ConnectionError SSL pinning hash mismatch, TLS handshake failure, timeout, DNS resolution fail
SSLPinningError Invalid certificate hash or TLS client could not be created
HttpError Server responded with a non-2xx HTTP status code
RequestError Other request-level failures (malformed URL, etc.)
ResponseReadError Response body could not be read
InvalidMethodError Unsupported HTTP method
JSONParseError Native response could not be parsed as JSON (Flutter-side)

Note: SSL pinning mismatches surface as ConnectionError (not a specific TLS error type) because rustls wraps the failure as a connection-level error. Check the error message string for details like "hash does not match".

Architecture Overview #

Android Implementation #

  • Native Layer: Rust-based HTTP client with OpenSSL for TLS operations
  • FFI Bridge: Asynchronous FFI calls using Flutter's compute() function
  • Isolate Execution: Prevents UI blocking during network operations

iOS Implementation #

  • Native Layer: Swift implementation using URLSession with custom certificate validation
  • Method Channel: Direct communication between Dart and Swift code
  • Background Queue: Network operations executed on background threads

API Reference #

SecureClient #

The main class for performing secure HTTP requests with certificate pinning.

Constructor

final client = SecureClient();

Creates a singleton instance of the secure HTTP client.

Methods

httpRequest()

Performs an HTTP request with SSL certificate pinning.

Future<SmartResponse> httpRequest({
  required String method,
  required String url,
  Object? body,
  Map<String, String>? headers,
  String? encoding,
  required String certificateHash,
  required PinningMethod pinningMethod,
})

Parameters:

Parameter Type Description Required
method String HTTP method ('GET', 'POST', 'PUT', 'DELETE', etc.)
url String Target URL for the request
body Object? Request body (String, Map, or null)
headers Map<String, String>? HTTP headers as key-value pairs
encoding String? Character encoding (default: 'json')
certificateHash String Base64-encoded certificate or public key hash
pinningMethod PinningMethod Type of pinning validation to use

Returns: Future<SmartResponse> — Contains success, data, statusCode, error, and errorType fields.

Throws:

  • ArgumentError — If body is not a String, Map, or null
  • UnsupportedError — If platform is not Android or iOS

Note: Network and SSL errors are not thrown. They are returned inside the SmartResponse object with success: false and the corresponding errorType.

PinningMethod Enum #

Defines the certificate pinning validation strategy:

enum PinningMethod {
  certificate,              // Leaf certificate DER hash
  publicKey,                // Leaf public key (SPKI) hash
  intermediateCertificate,  // Intermediate CA certificate DER hash
  intermediatePublicKey,    // Intermediate CA public key (SPKI) hash
}

Extension Methods

extension PinningMethodExtension on PinningMethod {
  String get value; // Returns string representation for native calls
}
Enum Value Native String Use Case
certificate "certificate" Own server, maximum strictness
publicKey "publickey" Own server, flexible renewals
intermediateCertificate "intermediatecertificate" CDN/WAF, stricter intermediate check
intermediatePublicKey "intermediatepublickey" CDN/WAF, maximum stability ✅

Utility Functions #

parseResponse(String response)

Parses and validates HTTP responses for SSL pinning errors.

String parseResponse(String response)

Parameters:

  • response - Raw response string from native layer

Returns: Validated response string

Throws: Exception if response contains connection errors

Example Application #

The plugin includes a comprehensive example app demonstrating:

  • Interactive SSL Pinning Testing: Real-time validation with multiple endpoints
  • Performance Benchmarking Suite: Detailed performance analysis tools
  • Visual Metrics Dashboard: Charts comparing standard vs secure clients
  • Error Handling Demonstrations: Examples of handling various failure scenarios
  • Best Practices Guide: Implementation patterns and security recommendations

To run the example:

cd example
flutter run

Platform Support #

Platform Status Implementation
Android ✅ Fully Supported FFI + Rust + OpenSSL
iOS ✅ Fully Supported Method Channel + Swift + URLSession
Web ❌ Not Supported Browser security limitations
Desktop ❌ Not Supported Planned for future releases

Security Considerations #

  • Certificate Rotation: Use public key pinning for easier certificate updates
  • CDN/WAF Services: Use intermediatePublicKey — Leaf certificates vary across edge nodes and rotate frequently
  • Backup Pins: Consider implementing backup certificate pins for redundancy
  • Pin Updates: Implement a strategy for updating certificate hashes in production
  • Fallback Strategy: Plan for graceful degradation if pinning fails
  • Testing: Thoroughly test pinning with staging environments before production
  • Pin Stability: Intermediate CA public keys typically last 5–10 years vs 90 days for Leaf certificates

Troubleshooting #

Common Issues #

  1. SSL Pinning Error: Certificate hash mismatch

    • Verify the certificate hash is correct and up-to-date
    • Check if the certificate has been renewed
  2. Platform Not Supported: Using on unsupported platforms

    • Ensure you're running on Android or iOS
    • Check minimum version requirements
  3. Network Timeouts: Slow network responses

    • Consider implementing timeout handling
    • Use performance benchmarking to identify bottlenecks

Contributing #

We welcome contributions! Please see our contributing guidelines and code of conduct.

License #

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog #

See CHANGELOG.md for detailed version history and updates.

3
likes
150
points
65
downloads

Publisher

verified publishersmart-dev.com.co

Weekly Downloads

This plugin creates a secure native TLS connection to execute HTTP requests with certificate pinning.

Homepage

Documentation

API reference

License

MIT (license)

Dependencies

ffi, flutter, plugin_platform_interface

More

Packages that depend on smart_dev_pinning_plugin

Packages that implement smart_dev_pinning_plugin