Turkish e-signature certificates (NES — Nitelikli Elektronik Sertifika) expire after 1-3 years. When they do, your company can't sign e-invoices, e-ledgers, or court filings. Here's how to build a monitoring system.
The Problem
Monday morning, 09:01 AM:
"Mali Mühür sertifikası süresi dolmuş, e-fatura kesemiyoruz!"
Revenue lost: ₺0 (but compliance violated)
Penalty risk: ₺100,000+ (GİB cezası)
Reputation: Damaged (client invoices delayed)
Certificate Structure
Turkish e-signature certificates follow X.509v3:
Certificate:
Version: 3
Serial Number: 4a:2b:3c:...
Issuer: C=TR, O=Kamu SM, CN=Kamu SM NES
Validity:
Not Before: Sep 22 00:00:00 2025 GMT
Not After: Sep 22 23:59:59 2026 GMT ← This is what we monitor
Subject: CN=ACME LTD ŞTİ, SERIALNUMBER=1234567890
Subject Public Key Info:
RSA 2048-bit
X509v3 Extensions:
Key Usage: Digital Signature, Non-Repudiation
QCStatements: id-etsi-qcs-QcCompliance ← Qualified certificate
JavaScript Certificate Parser
class CertificateMonitor {
/**
* Parse a PEM or DER certificate and extract expiry
* For browser-based monitoring dashboards
*/
static parsePEM(pemString) {
// Extract base64 content between headers
const b64 = pemString
.replace(/-----BEGIN CERTIFICATE-----/, '')
.replace(/-----END CERTIFICATE-----/, '')
.replace(/\s/g, '');
const binary = atob(b64);
const bytes = new Uint8Array(binary.length);
for (let i = 0; i < binary.length; i++) {
bytes[i] = binary.charCodeAt(i);
}
return this.parseDER(bytes);
}
static parseDER(bytes) {
// Simplified ASN.1 parser for X.509 validity dates
// In production, use a library like pkijs or asn1js
const hex = Array.from(bytes).map(b =>
b.toString(16).padStart(2, '0')
).join('');
// Find UTCTime or GeneralizedTime for notAfter
// UTCTime tag: 0x17, GeneralizedTime tag: 0x18
const utcTimePattern = /17(\w{2})(\w+)/g;
const times = [];
let match;
while ((match = utcTimePattern.exec(hex)) !== null) {
const len = parseInt(match[1], 16);
const timeHex = match[2].substring(0, len * 2);
const timeStr = this.hexToAscii(timeHex);
times.push(this.parseUTCTime(timeStr));
}
// Second UTCTime is notAfter
return {
notBefore: times[0] || null,
notAfter: times[1] || null,
daysRemaining: times[1] ?
Math.ceil((times[1] - new Date()) / 86400000) : null
};
}
static hexToAscii(hex) {
let str = '';
for (let i = 0; i < hex.length; i += 2) {
str += String.fromCharCode(parseInt(hex.substr(i, 2), 16));
}
return str;
}
static parseUTCTime(str) {
// Format: YYMMDDHHMMSSZ
const year = parseInt(str.substr(0, 2));
const fullYear = year >= 50 ? 1900 + year : 2000 + year;
return new Date(
fullYear,
parseInt(str.substr(2, 2)) - 1,
parseInt(str.substr(4, 2)),
parseInt(str.substr(6, 2)),
parseInt(str.substr(8, 2)),
parseInt(str.substr(10, 2))
);
}
}
// Alert thresholds
function checkCertificates(certs) {
const alerts = [];
for (const cert of certs) {
const days = cert.daysRemaining;
if (days <= 0) {
alerts.push({ level: 'CRITICAL', message: `EXPIRED ${Math.abs(days)} days ago`, cert });
} else if (days <= 7) {
alerts.push({ level: 'CRITICAL', message: `Expires in ${days} days`, cert });
} else if (days <= 30) {
alerts.push({ level: 'WARNING', message: `Expires in ${days} days`, cert });
} else if (days <= 90) {
alerts.push({ level: 'INFO', message: `Expires in ${days} days`, cert });
}
}
return alerts;
}
Monitoring Dashboard Architecture
┌──────────────────────────────────────────┐
│ Certificate Monitor │
│ │
│ ┌────────┐ ┌────────┐ ┌────────┐ │
│ │Mali │ │E-İmza │ │SSL/TLS │ │
│ │Mühür │ │NES │ │Server │ │
│ │45 gün │ │120 gün │ │230 gün │ │
│ │ ⚠️ │ │ ✅ │ │ ✅ │ │
│ └────────┘ └────────┘ └────────┘ │
│ │
│ Alert Rules: │
│ • 90 days → Email to IT │
│ • 30 days → Email to CEO + IT │
│ • 7 days → SMS + Slack + Email │
│ • 0 days → 🚨 EMERGENCY │
└──────────────────────────────────────────┘
Our Open-Source Solution
We built mali-muhur-eimza-suresi-kontrol — a Windows tool that scans all connected USB tokens and reports certificate expiry dates.
All tools: github.com/eimza-kep
Top comments (0)