Use of a Key Past its Expiration Date
Description
Use of a Key Past its Expiration Date is a vulnerability that occurs when a product uses cryptographic keys or passwords beyond their intended expiration dates. Cryptographic keys have expiration dates to limit the window during which a compromised key can be used, to ensure keys are refreshed with stronger algorithms over time, and to enforce good key management practices. When applications continue using expired keys, they extend the risk window for brute force attacks, may use outdated cryptographic strength, and undermine the key lifecycle management designed to maintain security.
Risk
Using expired cryptographic keys significantly increases security risk through several mechanisms. Extended key lifetime increases the total volume of data encrypted with that key, providing more material for cryptanalysis. Longer usage windows increase the probability of key compromise through operational exposure. Expired keys may use outdated key lengths or algorithms that have become vulnerable. Organizations may stop protecting keys after intended expiration, assuming they're no longer in use. Certificate expiration serves as a lifecycle management checkpoint - ignoring it removes this safeguard. The risk compounds over time: keys in use for years accumulate exposure through backups, logs, personnel changes, and potential breaches. Continued trust in expired credentials also signals poor security practices that may extend to other areas.
Solution
Implement proper key lifecycle management that enforces expiration dates. Check key and certificate expiration dates before use and reject expired credentials. Implement automated key rotation that generates and distributes new keys before expiration. Notify users and administrators before key expiration with clear guidance on renewal. Design systems to gracefully handle key transitions without service interruption. Maintain key inventories tracking all keys and their expiration dates. Use certificate management systems that automate renewal processes. For passwords, implement aging policies that require periodic changes. Configure systems to refuse connections using expired certificates. Implement monitoring and alerting for approaching key expirations.
Common Consequences
| Impact | Details |
|---|---|
| Access Control | Scope: Access Control Expired keys that have been compromised can continue to be used for authentication or decryption, allowing attackers to impersonate legitimate users or access protected data. |
| Confidentiality | Scope: Confidentiality Data protected by expired keys may be at increased risk if the keys have been compromised during their extended use beyond the intended security window. |
Example Code
Vulnerable Code (C/Java)
The following examples demonstrate accepting expired certificates and keys:
// Vulnerable: SSL certificate validation ignoring expiration
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <time.h>
int vulnerable_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
int err = X509_STORE_CTX_get_error(ctx);
// Check not-yet-valid
if (err == X509_V_ERR_CERT_NOT_YET_VALID) {
return 0; // Reject
}
// Vulnerable: No check for expiration!
// X509_V_ERR_CERT_HAS_EXPIRED is not handled
// Expired certificates are accepted!
return preverify_ok;
}
// Vulnerable: Manual check missing expiration
int vulnerable_check_certificate(X509 *cert) {
// Check if certificate is valid yet
if (X509_cmp_time(X509_get_notBefore(cert), NULL) > 0) {
return 0; // Not yet valid
}
// Vulnerable: Missing expiration check!
// Should check: X509_cmp_time(X509_get_notAfter(cert), NULL) < 0
return 1; // Accepts expired certificates!
}
// Vulnerable: API key without expiration check
typedef struct {
char key[64];
time_t created;
time_t expires; // Set but never checked!
} ApiKey;
int vulnerable_validate_api_key(ApiKey *key) {
// Vulnerable: Only checks if key exists
if (strlen(key->key) > 0) {
return 1; // Valid - but may be expired!
}
return 0;
}
// Vulnerable: Java certificate validation ignoring expiration
import java.security.cert.*;
import javax.net.ssl.*;
public class VulnerableCertValidator {
// Vulnerable: Custom TrustManager ignoring expiration
public static TrustManager[] getVulnerableTrustManagers() {
return new TrustManager[] {
new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String auth) {
// Vulnerable: No expiration check!
}
public void checkServerTrusted(X509Certificate[] chain, String auth)
throws CertificateException {
for (X509Certificate cert : chain) {
// Vulnerable: Only checks if not yet valid
try {
cert.checkValidity();
} catch (CertificateNotYetValidException e) {
throw e; // Reject not-yet-valid
} catch (CertificateExpiredException e) {
// Vulnerable: Ignoring expiration!
System.out.println("Warning: Certificate expired (ignored)");
}
}
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
}
};
}
// Vulnerable: License key without expiration enforcement
public boolean validateLicense(LicenseKey license) {
// Vulnerable: Only validates signature, not expiration
return license.verifySignature();
// license.getExpirationDate() is never checked!
}
}
# Vulnerable: Python certificate handling ignoring expiration
import ssl
from datetime import datetime
from cryptography import x509
def vulnerable_validate_certificate(cert_pem):
cert = x509.load_pem_x509_certificate(cert_pem.encode())
# Check if certificate is valid yet
if cert.not_valid_before > datetime.utcnow():
return False # Not yet valid
# Vulnerable: No expiration check!
# Should check: cert.not_valid_after < datetime.utcnow()
return True # Accepts expired certificates!
# Vulnerable: JWT token without expiration check
import jwt
def vulnerable_validate_token(token, secret):
try:
# Vulnerable: Not verifying expiration
payload = jwt.decode(
token,
secret,
algorithms=['HS256'],
options={'verify_exp': False} # Expiration check disabled!
)
return payload
except jwt.InvalidTokenError:
return None
Fixed Code (C/Java)
// Fixed: Proper certificate expiration validation
#include <openssl/ssl.h>
#include <openssl/x509.h>
#include <time.h>
int strict_verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
if (!preverify_ok) {
int err = X509_STORE_CTX_get_error(ctx);
// Fixed: Explicitly handle expiration errors
if (err == X509_V_ERR_CERT_HAS_EXPIRED) {
X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
char subject[256];
X509_NAME_oneline(X509_get_subject_name(cert), subject, sizeof(subject));
fprintf(stderr, "Certificate expired: %s\n", subject);
return 0; // Reject expired certificates
}
if (err == X509_V_ERR_CERT_NOT_YET_VALID) {
return 0; // Reject not-yet-valid
}
return 0; // Reject all other errors
}
return 1;
}
// Fixed: Complete certificate validity check
int secure_check_certificate(X509 *cert) {
time_t now = time(NULL);
// Fixed: Check not-yet-valid
if (X509_cmp_time(X509_get0_notBefore(cert), &now) > 0) {
fprintf(stderr, "Certificate not yet valid\n");
return 0;
}
// Fixed: Check expiration
if (X509_cmp_time(X509_get0_notAfter(cert), &now) < 0) {
fprintf(stderr, "Certificate has expired\n");
return 0;
}
// Fixed: Warning for certificates expiring soon
time_t warning_threshold = now + (30 * 24 * 60 * 60); // 30 days
if (X509_cmp_time(X509_get0_notAfter(cert), &warning_threshold) < 0) {
fprintf(stderr, "Warning: Certificate expires within 30 days\n");
}
return 1;
}
// Fixed: API key with expiration enforcement
typedef struct {
char key[64];
time_t created;
time_t expires;
} ApiKey;
int secure_validate_api_key(ApiKey *key) {
if (strlen(key->key) == 0) {
return 0; // Empty key
}
// Fixed: Check expiration
time_t now = time(NULL);
if (now > key->expires) {
fprintf(stderr, "API key has expired\n");
return 0; // Reject expired keys
}
// Fixed: Warning for keys expiring soon
if (now > key->expires - (7 * 24 * 60 * 60)) { // 7 days
fprintf(stderr, "Warning: API key expires soon\n");
}
return 1;
}
// Fixed: Java certificate validation with proper expiration checking
import java.security.cert.*;
import javax.net.ssl.*;
import java.util.Date;
public class SecureCertValidator {
// Fixed: TrustManager that properly checks expiration
public static SSLContext getSecureSSLContext() throws Exception {
// Use default trust manager which checks expiration
TrustManagerFactory tmf = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
tmf.init((KeyStore) null);
SSLContext sslContext = SSLContext.getInstance("TLSv1.3");
sslContext.init(null, tmf.getTrustManagers(), null);
return sslContext;
}
// Fixed: Explicit expiration check for additional validation
public static void validateCertificateExpiration(X509Certificate cert)
throws CertificateException {
Date now = new Date();
// Fixed: Check if certificate is valid (includes expiration)
try {
cert.checkValidity(now);
} catch (CertificateExpiredException e) {
throw new CertificateException("Certificate has expired", e);
} catch (CertificateNotYetValidException e) {
throw new CertificateException("Certificate not yet valid", e);
}
// Fixed: Warn if expiring soon
Date warningDate = new Date(System.currentTimeMillis() +
30L * 24 * 60 * 60 * 1000); // 30 days
if (cert.getNotAfter().before(warningDate)) {
System.err.println("Warning: Certificate expires on " +
cert.getNotAfter());
}
}
// Fixed: License validation with expiration
public boolean validateLicense(LicenseKey license) {
// Fixed: Check signature
if (!license.verifySignature()) {
return false;
}
// Fixed: Check expiration
Date now = new Date();
if (license.getExpirationDate().before(now)) {
System.err.println("License has expired");
return false;
}
return true;
}
}
# Fixed: Proper expiration validation
from datetime import datetime, timedelta
from cryptography import x509
import jwt
def secure_validate_certificate(cert_pem):
cert = x509.load_pem_x509_certificate(cert_pem.encode())
now = datetime.utcnow()
# Fixed: Check not-yet-valid
if cert.not_valid_before > now:
raise ValueError("Certificate not yet valid")
# Fixed: Check expiration
if cert.not_valid_after < now:
raise ValueError("Certificate has expired")
# Fixed: Warning for certificates expiring soon
warning_threshold = now + timedelta(days=30)
if cert.not_valid_after < warning_threshold:
print(f"Warning: Certificate expires on {cert.not_valid_after}")
return True
# Fixed: JWT with expiration verification
def secure_validate_token(token, secret):
try:
# Fixed: Verify expiration (default behavior)
payload = jwt.decode(
token,
secret,
algorithms=['HS256'],
options={
'verify_exp': True, # Verify expiration (default)
'require': ['exp', 'iat'] # Require these claims
}
)
return payload
except jwt.ExpiredSignatureError:
raise ValueError("Token has expired")
except jwt.InvalidTokenError as e:
raise ValueError(f"Invalid token: {e}")
# Fixed: API key validation with expiration
class SecureApiKeyValidator:
def validate(self, api_key):
key_record = self.get_key_record(api_key)
if not key_record:
return False
# Fixed: Check expiration
now = datetime.utcnow()
if key_record.expires_at < now:
self.log_expired_key_use(api_key)
return False
# Fixed: Warn about soon-expiring keys
if key_record.expires_at < now + timedelta(days=7):
self.notify_key_expiration(api_key, key_record.expires_at)
return True
The fix properly validates expiration dates and rejects expired credentials.
Exploited in the Wild
Hospital PACS System (Healthcare, 2021)
CVE-2021-33020 documented a hospital PACS (Picture Archiving and Communication System) that used cryptographic keys past their expiration dates, compromising patient data security.
Expired Certificate Acceptance (Various, Ongoing)
Multiple applications have been found accepting expired SSL/TLS certificates, enabling man-in-the-middle attacks.
Tools to Test/Exploit
-
testssl.sh — Command-line tool for testing SSL/TLS including certificate expiration.
-
OpenSSL — Tools for examining certificate validity periods.
-
Certificate Monitoring Services — Online tools to check certificate status.
CVE Examples
- CVE-2021-33020 — Hospital system using keys past expiration.
References
-
MITRE Corporation. "CWE-324: Use of a Key Past its Expiration Date." Common Weakness Enumeration. https://cwe.mitre.org/data/definitions/324.html
-
NIST. "Recommendation for Key Management." SP 800-57. https://csrc.nist.gov/publications/detail/sp/800-57-part-1/rev-5/final
-
OWASP Foundation. "Key Management Cheat Sheet." https://cheatsheetseries.owasp.org/cheatsheets/Key_Management_Cheat_Sheet.html