Biblioteca .NET para operaciones de firma digital usando firmas XAdES, específicamente diseñada para facturación electrónica SRI (Servicio de Rentas Internas) en Ecuador.
$ dotnet add package Yamgooo.SRI.SignA 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
dotnet add package Yamgooo.SRI.Sign
git clone https://github.com/yamgooo/Sri.Sign.git
cd Sri.Sign
dotnet build
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}");
}
// Sign with specific certificate (no configuration needed)
var result = await sriSignService.SignAsync(
xmlContent,
"path/to/certificate.p12",
"your-password"
);
// 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);
{
"SriSign": {
"CertificatePath": "Certificates/certificate.p12",
"CertificatePassword": "your-secure-password",
"CertificateBase64": "MIIKsAIBAzCCCmwGCSqGSIb3DQEHAaCCCl0EggpZMIIKVTCCBQ...",
"Base64CertificatePassword": "your-base64-password"
}
}
// Register with configuration
services.AddSriSignService(configuration);
// Use the service
var sriSignService = serviceProvider.GetRequiredService<ISriSignService>();
var result = await sriSignService.SignAsync(xmlContent);
var config = new SriSignConfiguration
{
CertificatePath = "path/to/certificate.p12",
CertificatePassword = "your-password",
CertificateBase64 = "MIIKsAIBAzCCCmwGCSqGSIb3DQEHAaCCCl0EggpZMIIKVTCCBQ...",
Base64CertificatePassword = "your-base64-password"
};
services.AddSriSignService(config);
// 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);
// Validate a signed XML document
bool ValidateSignature(string signedXml);
// Validate a Base64 certificate
bool ValidateBase64Certificate(string certificateBase64, string password);
// 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);
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; }
}
// 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();
The service automatically validates:
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);
}
}
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);
}
}
}
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);
}
}
[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
}
The service is optimized for high-performance operations:
Typical performance metrics:
git checkout -b feature/amazing-feature)git commit -m 'Add some amazing feature')git push origin feature/amazing-feature)This project is licensed under the MIT License - see the LICENSE file for details.
Made with ❤️ for the Ecuadorian developer community