Skip to content

Instantly share code, notes, and snippets.

@mcalero11
Created June 7, 2025 18:00
Show Gist options
  • Select an option

  • Save mcalero11/03af55c0e9872407b121dd77cc41f833 to your computer and use it in GitHub Desktop.

Select an option

Save mcalero11/03af55c0e9872407b121dd77cc41f833 to your computer and use it in GitHub Desktop.
Test Certificate Generator for SVFE API Firmador

Test Certificate Generator for SVFE API Firmador

A bash script to generate valid test certificates for the El Salvador Electronic Tax Document (DTE) signing API.

Overview

This script generates XML certificates in the custom format required by the SVFE (Sistema de Facturación Virtual Electrónica) API for document signing. The certificates contain RSA key pairs and are compatible with the Java Spring Boot application that handles DTE digital signatures.

Features

  • ✅ Generates valid XML certificates that work with the SVFE API
  • ✅ Uses proper RSA-2048 key pairs in Base64 DER format
  • ✅ Creates SHA512 password hashes for authentication
  • ✅ Supports custom NIT (tax ID) and password combinations
  • ✅ Uses epoch timestamps compatible with Jackson JavaTimeModule
  • ✅ Produces certificates ready for document signing operations

Usage

# Make the script executable
chmod +x generate_test_certificate.sh

# Generate certificate with default values
./generate_test_certificate.sh

# Generate certificate with custom NIT and password
./generate_test_certificate.sh "12345678901234" "mypassword123"

Parameters

  1. NIT (optional): 14-digit tax identification number (default: "12345678901234")
  2. Password (optional): Private key password (default: "test123")

Output

The script generates a .crt file named after the NIT containing:

  • Public Key: RSA-2048 public key in X.509 format
  • Private Key: RSA-2048 private key in PKCS#8 format
  • Certificate Metadata: Issuer, subject, validity periods, extensions
  • Password Hashes: SHA512 hashes for key authentication

Certificate Format

The generated certificates use a custom XML format specific to the El Salvador Ministry of Finance (Ministerio de Hacienda) requirements:

<CertificadoMH>
  <_id>mongodb_object_id</_id>
  <nit>tax_identification_number</nit>
  <publicKey>
    <keyType>PUBLIC</keyType>
    <algorithm>RSA</algorithm>
    <encodied>base64_encoded_public_key</encodied>
    <format>X.509</format>
    <clave>sha512_hash</clave>
  </publicKey>
  <privateKey>
    <keyType>PRIVATE</keyType>
    <algorithm>RSA</algorithm>
    <encodied>base64_encoded_private_key</encodied>
    <format>PKCS#8</format>
    <clave>sha512_password_hash</clave>
  </privateKey>
  <!-- Additional certificate metadata -->
</CertificadoMH>

API Integration

After generating a certificate, copy it to your application's upload directory and test with:

# Copy certificate to uploads directory
cp [NIT].crt uploads/

# Test API endpoint
curl -X POST http://localhost:8113/firmardocumento/ \
  -H 'Content-Type: application/json' \
  -d '{
    "nit": "your_nit_here",
    "passwordPri": "your_password_here",
    "dteJson": {"test": "document"}
  }'

Technical Details

Cryptographic Specifications

  • Algorithm: RSA-2048
  • Signature Algorithm: RSA-SHA512 (RS512)
  • Key Format: PKCS#8 (private), X.509 (public)
  • Encoding: Base64 DER
  • Hash Function: SHA512 for password validation

Certificate Authority Information

  • Issuer: Ministerio de Hacienda - El Salvador
  • Organization: Dirección General de Impuestos Internos
  • Validity: 1 year from generation date
  • Key Usage: Digital Signature, Content Commitment

Security Notes

⚠️ IMPORTANT: These are test certificates for development purposes only!

  • The RSA key pairs are hardcoded and publicly available
  • Do NOT use these certificates in production environments
  • For production, use certificates issued by the official El Salvador CA
  • Private keys should be generated securely and kept confidential

Compatibility

  • Java Spring Boot: Compatible with Jackson XML parsing
  • JOSE4J: Works with JSON Web Signature (JWS) creation
  • BouncyCastle: Compatible with RSA key operations
  • OpenSSL: Uses OpenSSL for hash generation

Dependencies

  • bash (shell environment)
  • openssl (for SHA512 hash generation)
  • date (for timestamp generation)

Error Handling

The script includes validation for common issues:

  • Ensures proper password hash generation
  • Uses epoch timestamps for date compatibility
  • Generates valid MongoDB-style object IDs
  • Creates properly formatted XML structure

License

This script is provided for educational and testing purposes. Use in accordance with El Salvador's electronic invoicing regulations and your organization's security policies.


Generated for: El Salvador Electronic Tax Document (DTE) System
Compatible with: SVFE API Firmador (Java Spring Boot)
Last Updated: June 2024

#!/bin/bash
# Script to generate a test certificate for the svfe-api-firmador project
# Usage: ./generate_test_certificate.sh [NIT] [private_key_password]
# Default values
NIT=${1:-"12345678901234"}
PRIVATE_PASSWORD=${2:-"test123"}
PUBLIC_PASSWORD="public123"
echo "Generating test certificate for NIT: $NIT"
echo "Private key password: $PRIVATE_PASSWORD"
# Hardcoded RSA key pair (2048-bit) - Base64 encoded DER format
# These are test keys - DO NOT use in production!
# Private key (PKCS#8 format)
PRIVATE_KEY_B64="MIIEwAIBADANBgkqhkiG9w0BAQEFAASCBKowggSmAgEAAoIBAQCoJdrM7gRYxzicb4v38AtAfq7E4Rv90rtuXk96fDGIO4d9YHUMam5ZmrFFkK4PBAErm5dmMj1IWzX1u7/L4Gqe63MXbg0lcfbWJhIw3YHXPhqQo8vHgsXs6znRviwAEVm5TS6emm1dcnVJ3MO26npob4RdILvjzT63AdPVoeLVc9Y0f/agqaiOQCgEbMGa53ueVT/9+m2fn2xxefYN5A8isFaBuegSiaNUYMwA8SrgjWweU8M6g2t8fcMtSOqydNKvzRrZ6ZLGfqrnVj6IEA+0tT+K8I4NiJtBjKrbRHqYZtkpWuwt8eGOzygyBUmV+uSbeycqp30phQ6kC7hGIqe7AgMBAAECggEBAIH7CUFjON772cor/FIEMF6Bz04ICeBTV2pA40V23b9G7TzBJJodaAJCL4jsB3E6EkGIfCeW7IKTZ4n2wZOzfhgtQAG7o9PvXfU65tL5WBZwPo7S34Lxl1jGmSKG1HKU9vvkKwaVr7cN9JbNXkl2xnsWwYZP+I5nKXTEp+E7zCJdsTxI4SCcmULdvTQhyXzmceAw2O2mepNZ+Z64D+g4VwEcV82Lh6nXptXl4FniTrMD0vC/vYP1qkt7obhSBAPQZRFVrJjI9SmtcACM+rzCzfr9MgKkLtypCwfhbwrmnD/vsVFZy9kRg0g+/vfzLiNNLGLw5DlhGj5OkoDzeL+v9TkCgYEA1GnPucwwuPzQTUJic3nmEI2y8LrnuW5vgRFIkJ02C4kZM9qT/Wa/9sXBtmqstiOfLAD1OL4nMwRJyRBwq2MSE1KkJ1pkAd4EK+OM6NzPJh2RQmeEZYuNe2IkOIugdqUBZ76oVZnWfRPyc9dfPGJn99iyhH8hfMOzwqxGlaiJcu8CgYEAyqbBKzZIkTev5fygh06zsjX1VUH0SZxofsOOObF14cv+h31yjB+03yWeET9b9Jo7lwBlWKXKXSPMw7HuNjxEdZGB4K7JWt2zuag+KwvrIXWm89iraV8Ro1eTYkkk3wY4Pvcn21KqkWi8IrTBqWspnihm8O67/zKzSrT7acI+5/UCgYEAzUNvFCnIz4qnNHG5N8QNWePEjrLfKKcao4vzJqR1TJJww1Yu+oonaS3TMxdEzUIBGAHY9rtyn+896kmzxzsWhYuvy8OirtdACrV7Pq/akgeyjowAOiywTRIa1HXBW8W6ZOmuPAJMblQvUFhI1M53j99dK4K69pkbhjz6fLcAFAsCgYEAnudFHxowqtYMsn12bsLyuvH+jrzpzfK8KXI0Ct8xPT3VNu7SLDgMftGjcYjKFTH/OfeQgIN3+7K/tE/IJ3T4hWv0eHb14q9nZ1Qac2ykEheMMzcZqcVnMjrQkcgjBlJ9NjpdYWgf4WdL5rbwCGXEO4UYuyGn/oMF/bWOUq6C3yUCgYEAp00QIFovedelbNL388B7pgHfc6DdrRhx6wDEtlnack/dy5G5v3QqVlKkpRijxqrRQdAsFEL8eerR6GXKu5KNfwGLqV+EEn+cVL3x52ruscpD3No5IV3yZPbvEIeBh0eHs35K1fnWCJQcQ27nYqsGN5Rdjjr/qmnzY57+i7qJxOQ="
# Public key (X.509 format)
PUBLIC_KEY_B64="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqCXazO4EWMc4nG+L9/ALQH6uxOEb/dK7bl5PenwxiDuHfWB1DGpuWZqxRZCuDwQBK5uXZjI9SFs19bu/y+BqnutzF24NJXH21iYSMN2B1z4akKPLx4LF7Os50b4sABFZuU0unpptXXJ1SdzDtup6aG+EXSC7480+twHT1aHi1XPWNH/2oKmojkAoBGzBmud7nlU//fptn59scXn2DeQPIrBWgbnoEomjVGDMAPEq4I1sHlPDOoNrfH3DLUjqsnTSr80a2emSxn6q51Y+iBAPtLU/ivCODYibQYyq20R6mGbZKVrsLfHhjs8oMgVJlfrkm3snKqd9KYUOpAu4RiKnuwIDAQAB"
# Generate SHA512 hashes of passwords
PRIVATE_HASH=$(echo -n "$PRIVATE_PASSWORD" | openssl dgst -sha512 | cut -d' ' -f2)
PUBLIC_HASH=$(echo -n "$PUBLIC_PASSWORD" | openssl dgst -sha512 | cut -d' ' -f2)
# Get current date for certificate
CURRENT_DATE=$(date -u +"%Y-%m-%dY%H:%M:%S.%3NZ")
# Generate random MongoDB-style ID
MONGO_ID=$(openssl rand -hex 12)
# Generate epoch timestamps for validity
CURRENT_EPOCH=$(date +%s)
FUTURE_EPOCH=$((CURRENT_EPOCH + 31536000)) # +1 year
# Generate the XML certificate (single line, no formatting like the working example)
# Use simple epoch seconds for Jackson to parse as Instant
# Use correct SHA512 hash of the password for the private key clave field
cat > "${NIT}.crt" << EOF
<CertificadoMH><_id>$MONGO_ID</_id><nit>$NIT</nit><publicKey><keyType>PUBLIC</keyType><algorithm>RSA</algorithm><encodied>$PUBLIC_KEY_B64</encodied><format>X.509</format><clave>$PUBLIC_HASH</clave></publicKey><privateKey><keyType>PRIVATE</keyType><algorithm>RSA</algorithm><encodied>$PRIVATE_KEY_B64</encodied><format>PKCS#8</format><clave>$PRIVATE_HASH</clave></privateKey><activo>true</activo><certificado><basicEstructure><version>2</version><serial>1.2.840.113549.1.1.11</serial><signatureAlgorithm><algorithm>Sha256WithRSAEncryption</algorithm><parameters/></signatureAlgorithm><issuer><countryName>SV</countryName><localilyName>SAN SALVADOR</localilyName><organizationalUnit>MINISTERIO DE HACIENDA</organizationalUnit><organizationalName>DIRECCIÓN GENERAL DE IMPUESTOS INTERNOS</organizationalName><commonName>UNIDAD COORDINADORA DEL PROGAMA FORTALECIMIENTO A LA ADMINISTRACIÓN TRIBUTARÍA</commonName><organizationIdentifier>VATSV-0614-010111-003-2</organizationIdentifier></issuer><validity><notBefore>$CURRENT_EPOCH</notBefore><notAfter>$FUTURE_EPOCH</notAfter></validity><subject><countryName>El Salvador</countryName><organizationName>TEST COMPANY</organizationName><organizationUnitName>TEST DEPARTMENT</organizationUnitName><organizationIdentifier>VATSV$NIT</organizationIdentifier><surname>TEST</surname><givenName>USER</givenName><commonName>test</commonName><description>9999999</description></subject><subjectPublicKeyInfo><algorithmIdenitifier><algorithm>RSA</algorithm><parameters/></algorithmIdenitifier><subjectPublicKey>$PUBLIC_KEY_B64</subjectPublicKey></subjectPublicKeyInfo></basicEstructure><extensions><authorityKeyIdentifier><keyIdentifier>$MONGO_ID</keyIdentifier></authorityKeyIdentifier><subjectKeyIdentifier><keyIdentifier>${MONGO_ID}aa</keyIdentifier></subjectKeyIdentifier><keyUsage><digitalSignature>1</digitalSignature><contentCommintment>1</contentCommintment><dataEncipherment>0</dataEncipherment><keyAgreement>0</keyAgreement><keyCertificateSignature>0</keyCertificateSignature><crlSignature>0</crlSignature><encipherOnly>0</encipherOnly><decipherOnly>0</decipherOnly></keyUsage><certificatePolicies><policyInformations/></certificatePolicies><subjectAlternativeNames><rfc822Name>test@company.com</rfc822Name></subjectAlternativeNames><extendedKeyUsage><clientAuth></clientAuth><emailProtection></emailProtection></extendedKeyUsage><crlDistributionPoint><distributionPoint><distributionPoint>http://www2.mh.gob.sv/crl</distributionPoint><distributionPoint>http://www2.mh.gob.sv/crl2</distributionPoint></distributionPoint></crlDistributionPoint><authorityInfoAccess><accessDescription><accessDescription><accessMethod></accessMethod><accessLocation><accessLocation>https://www.minec.gob.sv/ca/public/donwload/subordinadal.crt</accessLocation></accessLocation></accessDescription></accessDescription></authorityInfoAccess><qualifiedCertificateStatements><qcCompliance></qcCompliance><qcEuRetentionPeriod>10</qcEuRetentionPeriod><qcPDS><pdsLocation/><url>https://www2.mh.gob.sv/pds</url><language>ES</language></qcPDS><qcType>id-etsi-qct-esign</qcType></qualifiedCertificateStatements><basicConstraints><ca>false</ca></basicConstraints></extensions></certificado><clavePub/><clavePri/></CertificadoMH>
EOF
# Certificate generated in current directory
echo ""
echo "✅ Certificate generated successfully!"
echo "📁 File: ${NIT}.crt"
echo "🔑 NIT: $NIT"
echo "🔒 Private Key Password: $PRIVATE_PASSWORD"
echo "🔓 Public Key Password: $PUBLIC_PASSWORD"
echo ""
echo "📋 Test API Request:"
echo "curl -X POST http://localhost:8113/firma/firmardocumento/ \\"
echo " -H 'Content-Type: application/json' \\"
echo " -d '{"
echo " \"nit\": \"$NIT\","
echo " \"passwordPri\": \"$PRIVATE_PASSWORD\","
echo " \"dteJson\": {\"test\": \"document\"}"
echo " }'"
echo ""
echo "📂 Copy this file to your application's upload directory"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment