Yamgooo.SRI.Sign 1.0.4

dotnet add package Yamgooo.SRI.Sign --version 1.0.4
                    
NuGet\Install-Package Yamgooo.SRI.Sign -Version 1.0.4
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Yamgooo.SRI.Sign" Version="1.0.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Yamgooo.SRI.Sign" Version="1.0.4" />
                    
Directory.Packages.props
<PackageReference Include="Yamgooo.SRI.Sign" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Yamgooo.SRI.Sign --version 1.0.4
                    
#r "nuget: Yamgooo.SRI.Sign, 1.0.4"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Yamgooo.SRI.Sign@1.0.4
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Yamgooo.SRI.Sign&version=1.0.4
                    
Install as a Cake Addin
#tool nuget:?package=Yamgooo.SRI.Sign&version=1.0.4
                    
Install as a Cake Tool

SRI Digital Signature Service

.NET License NuGet

A professional .NET library for digital signature operations using XAdES signatures, specifically designed for SRI (Servicio de Rentas Internas) electronic invoicing in Ecuador.

Also available in Spanish: README_es.md

๐Ÿš€ Features

  • XAdES Digital Signatures: Full support for XML Advanced Electronic Signatures
  • Certificate Management: Flexible certificate loading from P12/PFX files and Base64
  • Base64 Certificates: Full support for embedded Base64 certificates (ideal for cloud and containers)
  • Async Operations: High-performance asynchronous signature operations
  • Configuration Support: Multiple configuration options (appsettings.json, code-based, dynamic)
  • Validation: Built-in signature validation and certificate verification
  • Logging: Comprehensive logging with structured logging support
  • Error Handling: Robust error handling with detailed error messages
  • Performance Monitoring: Built-in performance metrics and timing

๐Ÿ“ฆ Installation

NuGet Package

dotnet add package Yamgooo.SRI.Sign

Manual Installation

git clone https://github.com/yamgooo/Sri.Sign.git
cd Sri.Sign
dotnet build

๐Ÿ› ๏ธ Quick Start

1. Basic Usage (Dynamic Configuration)

using Yamgooo.SRI.Sign;

// Register the service
services.AddSriSignService();

// Use the service
var sriSignService = serviceProvider.GetRequiredService<ISriSignService>();

// Set certificate dynamically
sriSignService.SetDefaultCertificate("path/to/certificate.p12", "your-password");

// Sign XML content
var result = await sriSignService.SignAsync(xmlContent);

if (result.Success)
{
    Console.WriteLine($"XML signed successfully in {result.ProcessingTimeMs}ms");
    var signedXml = result.SignedXml;
}
else
{
    Console.WriteLine($"Error: {result.ErrorMessage}");
}

2. Direct Certificate Usage

// Sign with specific certificate (no configuration needed)
var result = await sriSignService.SignAsync(
    xmlContent, 
    "path/to/certificate.p12", 
    "your-password"
);

3. Base64 Certificate Usage

// Sign with Base64 certificate (ideal for cloud and containers)
var result = await sriSignService.SignWithBase64CertificateAsync(
    xmlContent, 
    "MIIKsAIBAzCCCmwGCSqGSIb3DQEHAaCCCl0EggpZMIIKVTCCBQ...", 
    "your-password"
);

// Or set default Base64 certificate
sriSignService.SetDefaultBase64Certificate(certificateBase64, password);
var result = await sriSignService.SignWithDefaultBase64CertificateAsync(xmlContent);

4. Configuration-based Usage

appsettings.json
{
  "SriSign": {
    "CertificatePath": "Certificates/certificate.p12",
    "CertificatePassword": "your-secure-password",
    "CertificateBase64": "MIIKsAIBAzCCCmwGCSqGSIb3DQEHAaCCCl0EggpZMIIKVTCCBQ...",
    "Base64CertificatePassword": "your-base64-password"
  }
}
Program.cs
// Register with configuration
services.AddSriSignService(configuration);

// Use the service
var sriSignService = serviceProvider.GetRequiredService<ISriSignService>();
var result = await sriSignService.SignAsync(xmlContent);

5. Custom Configuration

var config = new SriSignConfiguration
{
    CertificatePath = "path/to/certificate.p12",
    CertificatePassword = "your-password",
    CertificateBase64 = "MIIKsAIBAzCCCmwGCSqGSIb3DQEHAaCCCl0EggpZMIIKVTCCBQ...",
    Base64CertificatePassword = "your-base64-password"
};

services.AddSriSignService(config);

๐Ÿ“‹ API Reference

ISriSignService Interface

SignAsync Methods
// Sign with default certificate configuration (prioritizes Base64 if configured)
Task<SignatureResult> SignAsync(string xmlContent);

// Sign with specific certificate
Task<SignatureResult> SignAsync(string xmlContent, string certificatePath, string password);

// Sign with specific Base64 certificate
Task<SignatureResult> SignWithBase64CertificateAsync(string xmlContent, string certificateBase64, string password);

// Sign with default Base64 certificate
Task<SignatureResult> SignWithDefaultBase64CertificateAsync(string xmlContent);
Validation
// Validate a signed XML document
bool ValidateSignature(string signedXml);

// Validate a Base64 certificate
bool ValidateBase64Certificate(string certificateBase64, string password);
Configuration
// Set default certificate for subsequent operations
void SetDefaultCertificate(string certificatePath, string password);

// Set default Base64 certificate for subsequent operations
void SetDefaultBase64Certificate(string certificateBase64, string password);

SignatureResult

public class SignatureResult
{
    public bool Success { get; set; }
    public string SignedXml { get; set; }
    public string ErrorMessage { get; set; }
    public DateTime SignatureTimestamp { get; set; }
    public long ProcessingTimeMs { get; set; }
}

๐Ÿ”ง Configuration Options

Service Registration Methods

// From appsettings.json
services.AddSriSignService(configuration, "SriSign");

// With custom configuration object
services.AddSriSignService(customConfig);

// With direct certificate parameters
services.AddSriSignService("certificate.p12", "password");

// Without configuration (for dynamic use)
services.AddSriSignService();

Configuration Validation

The service automatically validates:

  • Certificate file existence and accessibility
  • Certificate file size (1KB - 10MB)
  • Certificate password validity
  • Certificate expiration
  • Private key availability
  • Valid Base64 format for embedded certificates
  • Automatic Base64 format cleaning (line breaks, PEM headers, etc.)

๐Ÿ“ Examples

Base64 Certificate Example

public class Base64CertificateExample
{
    private readonly ISriSignService _sriSignService;

    public async Task<SignatureResult> SignWithBase64CertificateAsync(string xmlContent)
    {
        // Convert certificate file to Base64 (one-time operation)
        var certificateBytes = File.ReadAllBytes("certificate.p12");
        var certificateBase64 = Convert.ToBase64String(certificateBytes);
        var password = "your-password";

        // Validate Base64 certificate before using
        if (!_sriSignService.ValidateBase64Certificate(certificateBase64, password))
        {
            throw new InvalidOperationException("Invalid Base64 certificate");
        }

        // Sign with Base64 certificate
        return await _sriSignService.SignWithBase64CertificateAsync(xmlContent, certificateBase64, password);
    }

    public async Task<SignatureResult> SignWithConfiguredBase64Async(string xmlContent)
    {
        // Configure default Base64 certificate
        var certificateBase64 = Environment.GetEnvironmentVariable("SRI_CERTIFICATE_BASE64");
        var password = Environment.GetEnvironmentVariable("SRI_CERTIFICATE_PASSWORD");
        
        _sriSignService.SetDefaultBase64Certificate(certificateBase64, password);
        
        // Sign using default configuration
        return await _sriSignService.SignAsync(xmlContent);
    }
}

Complete SRI Invoice Signing Example

public class InvoiceSigningService
{
    private readonly ISriSignService _sriSignService;
    private readonly ILogger<InvoiceSigningService> _logger;

    public InvoiceSigningService(ISriSignService sriSignService, ILogger<InvoiceSigningService> logger)
    {
        _sriSignService = sriSignService;
        _logger = logger;
    }

    public async Task<SignatureResult> SignInvoiceAsync(string invoiceXml)
    {
        try
        {
            // Sign the invoice XML
            var result = await _sriSignService.SignAsync(invoiceXml);
            
            if (result.Success)
            {
                _logger.LogInformation("Invoice signed successfully");
                
                // Validate the signature
                if (_sriSignService.ValidateSignature(result.SignedXml))
                {
                    _logger.LogInformation("Signature validation passed");
                }
                else
                {
                    _logger.LogWarning("Signature validation failed");
                }
            }
            
            return result;
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error signing invoice");
            return SignatureResult.CreateFailure(ex.Message);
        }
    }
}

Multiple Certificate Management

public class MultiTenantSigningService
{
    private readonly ISriSignService _sriSignService;

    public async Task<SignatureResult> SignForTenantAsync(string xmlContent, string tenantId)
    {
        // Get tenant-specific certificate
        var certificatePath = GetTenantCertificatePath(tenantId);
        var certificatePassword = GetTenantCertificatePassword(tenantId);

        // Sign with tenant-specific certificate
        return await _sriSignService.SignAsync(xmlContent, certificatePath, certificatePassword);
    }
}

๐Ÿ”’ Security Considerations

  • Certificate Storage: Store certificates securely and never commit them to source control
  • Base64 Certificates: Ideal for containers and cloud services, store in environment variables or secret services
  • Password Management: Use secure configuration providers (Azure Key Vault, AWS Secrets Manager, etc.)
  • File Permissions: Ensure certificate files have appropriate access permissions
  • Network Security: Use HTTPS for all network communications
  • Logging: Be careful not to log sensitive information like certificate passwords
  • Certificate Rotation: Consider rotating certificates regularly, especially in production environments

๐Ÿงช Testing

Unit Testing Example

[Test]
public async Task SignAsync_WithValidXml_ReturnsSuccess()
{
    // Arrange
    var mockLogger = new Mock<ILogger<SriSignService>>();
    var service = new SriSignService(mockLogger.Object);
    
    var xmlContent = "<test>content</test>";
    var certificatePath = "test-cert.p12";
    var password = "test-password";

    // Act
    var result = await service.SignAsync(xmlContent, certificatePath, password);

    // Assert
    Assert.IsNotNull(result);
    // Add more specific assertions based on your test certificate
}

๐Ÿš€ Performance

The service is optimized for high-performance operations:

  • Async Operations: All I/O operations are asynchronous
  • Memory Efficient: Uses streaming for large XML documents
  • Caching: Certificate loading is optimized
  • Metrics: Built-in performance monitoring

Typical performance metrics:

  • Small XML (< 1KB): ~50-100ms
  • Medium XML (1-10KB): ~100-200ms
  • Large XML (10-100KB): ~200-500ms

๐Ÿ“ฆ Dependencies

  • .NET 9.0: Target framework
  • FirmaXadesNet: XAdES signature implementation
  • Microsoft.Extensions.Configuration: Configuration support
  • Microsoft.Extensions.Logging: Logging infrastructure
  • Microsoft.Extensions.Options: Options pattern support

๐Ÿค Contributing

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

๐Ÿ“„ License

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

๐Ÿ“ž Support


Made with โค๏ธ for the Ecuadorian developer community

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 was computed.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.4 381 9/13/2025
1.0.3 251 8/12/2025
1.0.2 220 8/11/2025
1.0.1 213 8/11/2025
1.0.0 281 8/8/2025