trustpin_sdk 1.2.0 copy "trustpin_sdk: ^1.2.0" to clipboard
trustpin_sdk: ^1.2.0 copied to clipboard

A Flutter plugin for TrustPin SSL certificate pinning SDK that provides enhanced security for network connections by validating SSL certificates against configured pins.

TrustPin SDK for Flutter #

pub package documentation license platform

A comprehensive Flutter plugin for TrustPin SSL certificate pinning that provides robust security against man-in-the-middle (MITM) attacks by validating server certificates against pre-configured public key pins.

๐ŸŒ Get started at TrustPin.cloud | ๐ŸŽฏ Manage your certificates in the Cloud Console

๐Ÿ“‹ Table of Contents #

๐Ÿš€ Features #

  • ๐Ÿ”’ SSL Certificate Pinning: Advanced certificate validation using SHA-256/SHA-512 public key pins
  • ๐Ÿ“‹ JWS-based Configuration: Securely fetch signed pinning configurations from TrustPin CDN
  • ๐ŸŒ Cross-platform Support: Native implementations for iOS (Swift), Android (Kotlin), and macOS (Swift)
  • โš™๏ธ Flexible Pinning Modes: Support for strict (production) and permissive (development) validation modes
  • ๐Ÿ”ง Comprehensive Error Handling: Detailed error types with programmatic checking capabilities
  • ๐Ÿ“Š Configurable Logging: Multiple log levels for debugging, monitoring, and production use
  • ๐Ÿ›ก๏ธ Thread Safety: Built with Flutter's async/await pattern and native concurrency models
  • โšก Intelligent Caching: 10-minute configuration caching with stale fallback for performance
  • ๐Ÿ” ECDSA P-256 Signature Verification: Cryptographic validation of configuration integrity
  • ๐Ÿš€ HTTP Client Integration: Built-in interceptors for popular HTTP clients (http, Dio)

๐Ÿ“ฆ Installation #

Add TrustPin SDK to your pubspec.yaml:

dependencies:
  trustpin_sdk: ^latest

Then install the package:

flutter pub get

Using Git (Development) #

For the latest development version:

dependencies:
  trustpin_sdk:
    git:
      url: https://github.com/trustpin-cloud/trustpin-libraries.git
      path: flutter/trustpin_sdk

๐Ÿ› ๏ธ Platform Setup #

iOS Requirements #

  • Minimum iOS Version: 13.0+
  • Xcode: 15.0+
  • Swift: 5.0+
  • Native Dependencies: TrustPin Swift SDK (automatically configured)

The iOS implementation uses the native TrustPin Swift SDK which is automatically linked via CocoaPods. No additional configuration required.

macOS Requirements #

  • Minimum macOS Version: 13.0+
  • Xcode: 15.0+
  • Swift: 5.0+
  • Native Dependencies: TrustPin Swift SDK (automatically configured)

The macOS implementation uses the same native TrustPin Swift SDK as iOS, automatically linked via CocoaPods. Requires network client entitlement for sandbox apps.

Android Requirements #

  • Minimum SDK: API 25 (Android 5.0)+
  • Target SDK: API 34+ (recommended)
  • Kotlin: 1.9.0+
  • Native Dependencies: TrustPin Kotlin SDK (automatically configured)

The Android implementation uses the native TrustPin Kotlin SDK which is automatically included via Gradle. No additional configuration required.

Network Permissions #

The SDK requires network access to fetch pinning configurations. Ensure your app has proper network permissions:

Android

The plugin automatically includes the required network permission in its AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />

iOS

Network access is enabled by default. For apps targeting iOS 14+, ensure your Info.plist allows network access to cdn.trustpin.cloud:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <false/>
    <key>NSExceptionDomains</key>
    <dict>
        <key>cdn.trustpin.cloud</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <false/>
            <key>NSExceptionMinimumTLSVersion</key>
            <string>TLSv1.2</string>
        </dict>
    </dict>
</dict>

macOS

For sandboxed macOS apps, add the network client entitlement to your entitlements files:

<!-- In DebugProfile.entitlements and Release.entitlements -->
<key>com.apple.security.network.client</key>
<true/>

For non-sandboxed apps, network access is enabled by default.

๐Ÿš€ Quick Start #

1. Get Your Credentials #

First, sign up at TrustPin Cloud Console and create a project to get your:

  • Organization ID
  • Project ID
  • Public Key (ECDSA P-256, Base64-encoded)

2. Initialize the SDK #

import 'package:trustpin_sdk/trustpin_sdk.dart';

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    _initializeTrustPin();
  }

  Future<void> _initializeTrustPin() async {
    try {
      // Set debug logging for development
      await TrustPin.setLogLevel(TrustPinLogLevel.debug);
      
      // Initialize with your credentials
      await TrustPin.setup(
        organizationId: 'your-org-id',
        projectId: 'your-project-id',
        publicKey: 'LS0tLS1CRUdJTi...', // Your Base64 public key
        mode: TrustPinMode.strict, // Use strict mode for production
      );
      
      print('TrustPin SDK initialized successfully!');
    } catch (e) {
      print('Failed to initialize TrustPin: $e');
    }
}

3. Verify Certificates #

Future<void> verifyServerCertificate() async {
  // Example PEM certificate (in practice, you'd get this from your HTTP client)
  const pemCertificate = '''
-----BEGIN CERTIFICATE-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7Q1jx8...
-----END CERTIFICATE-----
''';

  try {
    await TrustPin.verify('api.example.com', pemCertificate);
    print('โœ… Certificate is valid and matches configured pins!');
  } on TrustPinException catch (e) {
    print('โŒ Certificate verification failed: ${e.code} - ${e.message}');
    
    // Handle specific error types
    if (e.isPinsMismatch) {
      print('The certificate doesn\'t match any configured pins');
    } else if (e.isDomainNotRegistered) {
      print('Domain not configured for pinning (strict mode)');
    } else if (e.isAllPinsExpired) {
      print('All configured pins have expired');
    }
  } catch (e) {
    print('Unexpected error: $e');
  }
}

๐Ÿ’ผ Advanced Usage #

Integration with HTTP Clients #

Using with Dio

The SDK provides a built-in TrustPinDioInterceptor for seamless Dio integration:

import 'package:dio/dio.dart';
import 'package:trustpin_sdk/trustpin_sdk.dart';

// Create Dio instance with TrustPin certificate validation
final dio = Dio();
dio.interceptors.add(TrustPinDioInterceptor());

// All HTTPS requests will now have certificate pinning validation
try {
  final response = await dio.get('https://api.example.com/data');
  print('Request successful: ${response.statusCode}');
} on DioException catch (e) {
  if (e.error is TrustPinException) {
    final trustPinError = e.error as TrustPinException;
    print('Certificate pinning failed: ${trustPinError.code} - ${trustPinError.message}');
  } else {
    print('Request failed: ${e.message}');
  }
}

// The interceptor automatically:
// 1. Validates standard TLS certificates (OS-level validation)
// 2. Performs TrustPin certificate pinning validation
// 3. Caches certificates for performance
// 4. Prevents requests with invalid certificates

// Manage certificate cache if needed
final interceptor = TrustPinDioInterceptor();
dio.interceptors.add(interceptor);

// Clear all cached certificates
interceptor.clearCertificateCache();

Using with http package

The SDK provides a built-in TrustPinHttpClient that wraps the standard http.Client:

import 'package:http/http.dart' as http;
import 'package:trustpin_sdk/trustpin_sdk.dart';

// Create a TrustPin-enabled HTTP client
final httpClient = TrustPinHttpClient.create();

// Or wrap an existing client
final customClient = http.Client();
final httpClient = TrustPinHttpClient(customClient);

// Use it like a normal http.Client
final response = await httpClient.get(Uri.parse('https://api.example.com/data'));

// The client automatically:
// 1. Validates standard TLS certificates
// 2. Performs TrustPin certificate pinning
// 3. Caches certificates for performance

// Clear certificate cache if needed
httpClient.clearCertificateCache();

// Clean up when done
httpClient.close();

Environment-Specific Configuration #

class TrustPinConfig {
  static Future<void> initializeForEnvironment() async {
    const environment = String.fromEnvironment('ENVIRONMENT', defaultValue: 'development');
    
    switch (environment) {
      case 'production':
        await _initializeProduction();
        break;
      case 'staging':
        await _initializeStaging();
        break;
      default:
        await _initializeDevelopment();
    }
  }
  
  static Future<void> _initializeProduction() async {
    await TrustPin.setLogLevel(TrustPinLogLevel.error);
    await TrustPin.setup(
      organizationId: 'prod-org-123',
      projectId: 'prod-project-456',
      publicKey: 'LS0tLS1CRUdJTi...', // Production public key
      mode: TrustPinMode.strict,
    );
  }
  
  static Future<void> _initializeStaging() async {
    await TrustPin.setLogLevel(TrustPinLogLevel.info);
    await TrustPin.setup(
      organizationId: 'staging-org-123',
      projectId: 'staging-project-456', 
      publicKey: 'LS0tLS1CRUdJTi...', // Staging public key
      mode: TrustPinMode.strict,
    );
  }
  
  static Future<void> _initializeDevelopment() async {
    await TrustPin.setLogLevel(TrustPinLogLevel.debug);
    await TrustPin.setup(
      organizationId: 'dev-org-123',
      projectId: 'dev-project-456',
      publicKey: 'LS0tLS1CRUdJTi...', // Development public key
      mode: TrustPinMode.permissive, // Allow unpinned domains in development
    );
  }
}

// Usage in main.dart
void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  
  await TrustPinConfig.initializeForEnvironment();
  
  runApp(MyApp());
}

Error Handling Patterns #

class TrustPinErrorHandler {
  static void handleVerificationError(TrustPinException error, String domain) {
    // Log error for monitoring
    _logSecurityEvent(error, domain);
    
    switch (error.code) {
      case 'PINS_MISMATCH':
        _handlePinsMismatch(error, domain);
        break;
      case 'DOMAIN_NOT_REGISTERED':
        _handleDomainNotRegistered(error, domain);
        break;
      case 'ALL_PINS_EXPIRED':
        _handleAllPinsExpired(error, domain);
        break;
      case 'INVALID_SERVER_CERT':
        _handleInvalidCertificate(error, domain);
        break;
      case 'ERROR_FETCHING_PINNING_INFO':
        _handleNetworkError(error, domain);
        break;
      default:
        _handleUnknownError(error, domain);
    }
  }
  
  static void _handlePinsMismatch(TrustPinException error, String domain) {
    // Critical security issue - potential MITM attack
    print('๐Ÿšจ SECURITY ALERT: Certificate mismatch for $domain');
    // Consider blocking the request and alerting the user
  }
  
  static void _handleDomainNotRegistered(TrustPinException error, String domain) {
    print('โš ๏ธ Domain $domain not configured for pinning');
    // In strict mode, this might be intentional or an oversight
  }
  
  static void _handleAllPinsExpired(TrustPinException error, String domain) {
    print('โฐ All pins expired for $domain - update needed');
    // Consider allowing the request but log for monitoring
  }
  
  static void _handleInvalidCertificate(TrustPinException error, String domain) {
    print('โŒ Invalid certificate format for $domain');
    // This might indicate a parsing issue
  }
  
  static void _handleNetworkError(TrustPinException error, String domain) {
    print('๐ŸŒ Network error fetching pinning configuration');
    // Consider using cached configuration or fallback behavior
  }
  
  static void _handleUnknownError(TrustPinException error, String domain) {
    print('โ“ Unknown error for $domain: ${error.message}');
    // Log for investigation
  }
  
  static void _logSecurityEvent(TrustPinException error, String domain) {
    // Send to your security monitoring system
    final event = {
      'timestamp': DateTime.now().toIso8601String(),
      'domain': domain,
      'error_code': error.code,
      'error_message': error.message,
      'app_version': 'your-app-version',
    };
    
    // Send to your logging/monitoring service
    print('Security event logged: $event');
  }
}

// Usage
try {
  await TrustPin.verify('api.example.com', certificate);
} on TrustPinException catch (e) {
  TrustPinErrorHandler.handleVerificationError(e, 'api.example.com');
  // Decide whether to proceed with the request or abort
  rethrow; // Re-throw if you want to abort the request
}

๐Ÿ“š API Documentation #

For complete API documentation, visit our GitHub Pages Documentation.

TrustPin Class (Static Methods) #

TrustPin.setup()

Initializes the TrustPin SDK with your project credentials.

static Future<void> setup({
  required String organizationId,
  required String projectId,
  required String publicKey,
  Uri? configurationURL, // Optional custom URL for self-hosted configurations
  TrustPinMode mode = TrustPinMode.strict,
})

Parameters:

  • organizationId: Your organization identifier from the TrustPin dashboard
  • projectId: Your project identifier from the TrustPin dashboard
  • publicKey: Base64-encoded ECDSA P-256 public key for JWS verification
  • configurationURL: Optional custom URL for self-hosted configurations (null for CDN-managed)
  • mode: Pinning mode (strict or permissive)

Throws: TrustPinException if setup fails

TrustPin.verify()

Verifies a certificate against the configured pins for a domain.

static Future<void> verify(String domain, String certificate)

Parameters:

  • domain: The domain name to verify (e.g., "api.example.com")
  • certificate: PEM-encoded certificate string with BEGIN/END markers

Throws: TrustPinException if verification fails

TrustPin.setLogLevel()

Sets the logging level for TrustPin SDK.

static Future<void> setLogLevel(TrustPinLogLevel level)

TrustPinHttpClient Class #

A certificate pinning interceptor for the http package that wraps any http.Client.

Constructor

TrustPinHttpClient(http.Client inner)

Factory Constructor

factory TrustPinHttpClient.create()

Creates a TrustPinHttpClient with a default http.Client.

Methods

  • send(BaseRequest request): Sends HTTP request with certificate validation
  • clearCertificateCache(): Clears the internal certificate cache
  • close(): Closes the client and clears resources

TrustPinDioInterceptor Class #

A certificate pinning interceptor for the Dio HTTP client.

Constructor

TrustPinDioInterceptor()

Creates a new interceptor that validates certificates for all HTTPS requests made through Dio.

Methods

  • onRequest(RequestOptions, RequestInterceptorHandler): Validates certificates before sending requests
  • clearCertificateCache(): Clears the internal certificate cache

Enums #

TrustPinMode

Pinning modes that control behavior for unregistered domains:

  • TrustPinMode.strict: Throws errors for unregistered domains (recommended for production)
  • TrustPinMode.permissive: Allows unregistered domains to bypass pinning (development/testing)

TrustPinLogLevel

Log levels for controlling SDK output verbosity:

  • TrustPinLogLevel.none: No logging output
  • TrustPinLogLevel.error: Only error messages
  • TrustPinLogLevel.info: Error and informational messages
  • TrustPinLogLevel.debug: All messages including debug information

Exception Handling #

TrustPinException

Exception thrown by TrustPin operations with detailed error information:

Properties:

  • code: Error code identifying the type of error
  • message: Human-readable error message
  • details: Additional error details (may be null)

Error Types:

  • INVALID_PROJECT_CONFIG: Invalid setup parameters
  • ERROR_FETCHING_PINNING_INFO: CDN fetch failure
  • INVALID_SERVER_CERT: Invalid certificate format
  • PINS_MISMATCH: Certificate doesn't match configured pins
  • ALL_PINS_EXPIRED: All configured pins have expired
  • JWS_VALIDATION_FAILED: JWS signature validation failed
  • DOMAIN_NOT_REGISTERED: Domain not configured (strict mode only)
  • CONFIGURATION_VALIDATION_FAILED: Configuration validation failed

Helper Methods:

// Check specific error types
if (exception.isPinsMismatch) {
  // Handle certificate mismatch
}

if (exception.isDomainNotRegistered) {
  // Handle unregistered domain in strict mode
}

Example #

See the example/ directory for a complete sample application that demonstrates:

  • SDK initialization with credentials
  • Certificate verification
  • Error handling
  • Log level configuration

Security Considerations #

Production Deployment #

  1. Use Strict Mode: Always use TrustPinMode.strict in production
  2. Secure Credentials: Never commit credentials to version control
  3. Minimal Logging: Use TrustPinLogLevel.error or none in production
  4. Regular Updates: Keep pinning configurations up to date

Development and Testing #

  1. Permissive Mode: Use TrustPinMode.permissive for development
  2. Debug Logging: Enable TrustPinLogLevel.debug for troubleshooting
  3. Test Environment: Use separate credentials for testing

Platform-Specific Implementation #

iOS #

macOS #

Android #

  • Uses TrustPin Kotlin SDK from Maven (cloud.trustpin:kotlin-sdk:<<version>>)
  • Supports Android API 21 and later
  • Built with Kotlin coroutines
  • Multiplatform support (Android/JVM)

๐Ÿ” Security Best Practices #

Production Checklist #

  • โœ… Use TrustPinMode.strict mode
  • โœ… Set log level to TrustPinLogLevel.error or none
  • โœ… Store credentials securely (not in source code)
  • โœ… Implement proper error handling for certificate failures
  • โœ… Monitor certificate validation errors
  • โœ… Keep pinning configurations up to date
  • โœ… Test certificate validation in staging environment

Development Tips #

  • ๐Ÿ”ง Use TrustPinMode.permissive for development
  • ๐Ÿ”ง Enable TrustPinLogLevel.debug for troubleshooting
  • ๐Ÿ”ง Use separate credentials for different environments
  • ๐Ÿ”ง Test with both valid and invalid certificates
  • ๐Ÿ”ง Verify error handling works correctly

๐Ÿ“Š Performance Considerations #

  • Configuration Caching: Pinning configurations are cached for 10 minutes
  • Network Optimization: Initial setup requires one CDN request
  • Memory Usage: Minimal memory footprint with efficient native implementations
  • CPU Impact: Certificate validation is highly optimized in native code
  • Battery Life: Negligible impact on battery consumption

๐Ÿงช Testing #

The plugin includes comprehensive test coverage:

# Run unit tests
flutter test

# Run integration tests (requires device/emulator)
cd example
flutter test integration_test/plugin_integration_test.dart

# Run with coverage
flutter test --coverage

๐Ÿ“ฑ Example App #

The example/ directory contains a complete sample application demonstrating:

  • SDK initialization with different configurations
  • Certificate verification with various scenarios
  • Error handling patterns
  • Integration with HTTP clients
  • Environment-specific setup

To run the example:

cd example
flutter pub get
flutter run

๐Ÿš€ Migration Guide #

From Direct Native SDK Usage #

If you're currently using the native TrustPin SDKs directly:

  1. Replace native SDK imports:

    // Remove native imports
    // iOS: import TrustPinKit
    // Android: import cloud.trustpin.kotlin.sdk.TrustPin
       
    // Add Flutter plugin
    import 'package:trustpin_sdk/trustpin_sdk.dart';
    
  2. Update initialization:

    // Old (iOS)
    // try await TrustPin.setup(organizationId: "...", projectId: "...", publicKey: "...", mode: .strict)
       
    // Old (Android)  
    // val trustPin = TrustPin.create()
    // trustPin.setup("...", "...", "...")
       
    // New (Flutter) - Using static methods
    await TrustPin.setup(
      organizationId: 'your-org-id',
      projectId: 'your-project-id',
      publicKey: 'your-public-key',
      mode: TrustPinMode.strict,
    );
    
  3. Update certificate verification:

    // Old (iOS)
    // try await TrustPin.verify(domain: "api.example.com", certificate: pemCert)
       
    // Old (Android)
    // trustPin.verify("api.example.com", x509Certificate)
       
    // New (Flutter) - Using static methods
    await TrustPin.verify('api.example.com', pemCertificate);
    

๐Ÿค Contributing #

We welcome contributions! Please see our Contributing Guide for detailed information about:

  • Development environment setup
  • Code style guidelines
  • Testing requirements
  • Pull request process

Quick Contribution Steps #

  1. Fork the repository
  2. Create feature branch: git checkout -b feature/amazing-feature
  3. Make changes with tests
  4. Run quality checks:
    dart analyze --fatal-infos
    dart format --set-exit-if-changed .
    flutter test
    
  5. Create pull request with clear description

๐Ÿ“„ License #

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

๐Ÿ†˜ Support & Community #

Getting Help #

Professional Support #

Stay Updated #

  • โญ Star this repository to stay updated with releases
  • ๐Ÿ‘€ Watch for important security updates
  • ๐Ÿ“ข Follow @TrustPinCloud on Twitter

๐Ÿ”’ Secure your Flutter apps with TrustPin SSL Certificate Pinning ๐Ÿ”’

Get Started โ€ข Documentation โ€ข Support

3
likes
120
points
8
downloads

Publisher

verified publishertrustpin.cloud

Weekly Downloads

A Flutter plugin for TrustPin SSL certificate pinning SDK that provides enhanced security for network connections by validating SSL certificates against configured pins.

Repository (GitHub)
View/report issues

Documentation

Documentation
API reference

License

unknown (license)

Dependencies

dio, flutter, http, plugin_platform_interface

More

Packages that depend on trustpin_sdk

Packages that implement trustpin_sdk