OP.EXP.11 Protección de las claves criptográficas
Documentos de referencia
Referencias normativas ENS
- Real Decreto 311/2022 - Anexo II, Medida OP.EXP.11
- CCN-STIC-807 - Criptología de empleo en el ENS
- CCN-STIC-804 - Guía de Implantación del ENS
- CCN-STIC-822 - Guía para la Configuración Segura de Sistemas
Documentación interna Legit Health
- T-024-018 - Procedimiento de gestión de claves criptográficas
- T-024-019 - Política de uso de criptografía
- T-024-020 - Inventario de claves y certificados
- R-110-003 - Inventario de claves criptográficas ENS
- GP-013 - Gestión de Ciberseguridad
- T-110-007 - Matriz RACI de seguridad ENS
- T-110-008 - Procedimiento de notificación CCN-CERT
Referencias internacionales
- ISO/IEC 27001:2022 - Control A.8.24 (Uso de criptografía)
- NIST SP 800-57 - Recomendaciones para gestión de claves
- FIPS 140-2 - Módulos criptográficos
- Common Criteria - Evaluación de seguridad
Referencias médicas
- IEC 62304:2015 - Procesos de ciclo de vida del software de dispositivos médicos
- ISO 14971:2019 - Gestión de riesgos para dispositivos médicos
- MDR 2017/745 - Reglamento de Dispositivos Médicos
- FDA Cybersecurity Guidance - Orientación de ciberseguridad para dispositivos médicos
Guía de implantación
Objetivo
Establecer un sistema integral de protección, gestión y control del ciclo de vida completo de todas las claves criptográficas utilizadas en los sistemas de Legit Health, garantizando la seguridad del dispositivo médico y el cumplimiento de los requisitos regulatorios.
Alcance
Este procedimiento aplica a:
- Claves de cifrado de datos (AES, ChaCha20)
- Claves de firma digital (RSA, ECDSA, EdDSA)
- Certificados digitales (SSL/TLS, firma de código)
- Claves de autenticación (API keys, tokens)
- Secretos de aplicación (passwords, connection strings)
- Claves de cifrado de base de datos
- Material criptográfico del dispositivo médico
- Claves de backup y recuperación
Arquitectura de gestión de claves
3.1 Componentes del sistema
┌─────────────────────────────────────────┐
│ Hardware Security Module (HSM) │
│ FIPS 140-2 Level 3 Certified │
└───────────────────┬─────────────────────┘
│
┌────────────┴────────────┐
│ Key Management Service │
│ (AWS KMS / Azure) │
└───────┬─────────┬───────┘
│ │
┌─────────┴───┐ ┌───┴──────────┐
│ Secrets Vault │ │ Certificate │
│ (HashiCorp) │ │ Manager │
└─────────────┘ └──────────────┘
3.2 Jerarquía de claves
Master Key (HSM):
├─ Key Encryption Keys (KEK):
│ ├─ Data Encryption Keys (DEK)
│ ├─ Database Encryption Keys
│ └─ Backup Encryption Keys
│
├─ Signing Keys:
│ ├─ Code Signing Certificates
│ ├─ Document Signing Keys
│ └─ API Request Signing
│
└─ Authentication Keys:
├─ TLS/SSL Certificates
├─ SSH Keys
└─ Service Account Keys
Ciclo de vida de las claves
4.1 Generación de claves
Requisitos de generación:
def generate_cryptographic_key(key_type, purpose):
# Validar parámetros
validate_key_parameters(key_type, purpose)
# Configuración según tipo
if key_type == "SYMMETRIC":
key_spec = {
"algorithm": "AES",
"key_size": 256, # Bits
"mode": "GCM",
"source": "HSM"
}
elif key_type == "ASYMMETRIC":
key_spec = {
"algorithm": "RSA",
"key_size": 4096, # Bits mínimo
"padding": "OAEP",
"hash": "SHA-256"
}
elif key_type == "ELLIPTIC":
key_spec = {
"algorithm": "ECDSA",
"curve": "P-384", # secp384r1
"hash": "SHA-384"
}
# Generar con HSM/KMS
key = kms_client.generate_data_key(
KeyId=master_key_id,
KeySpec=key_spec,
EncryptionContext={'purpose': purpose}
)
# Registrar en inventario
register_key_metadata(key, purpose)
return key
Estándares mínimos:
Tipo | Algoritmo | Tamaño mínimo | Uso |
---|---|---|---|
Simétrico | AES-GCM | 256 bits | Cifrado de datos |
Asimétrico | RSA | 4096 bits | Firma, key exchange |
Elíptica | ECDSA | P-384 | Firma digital |
Hash | SHA | SHA-384 | Integridad |
KDF | PBKDF2 | 100,000 iter | Derivación |
4.2 Distribución segura
Mecanismos de distribución:
- Distribución automatizada (preferida):
Automated Distribution:
Method: Secrets Manager API
Authentication: IAM Role + MFA
Transport: TLS 1.3
Audit: CloudTrail enabled
Rotation: Automatic triggers
- Distribución manual (excepcional):
Manual Distribution:
Approval: CISO + Key Custodian
Method: Secure courier / HSM card
Envelope: Split knowledge (2 personas)
Verification: Out-of-band confirmation
Documentation: Chain of custody
Protocolo de intercambio seguro:
def secure_key_exchange(recipient_public_key, key_to_share):
# Generar clave efímera
ephemeral_key = generate_ephemeral_key()
# ECDH para secreto compartido
shared_secret = ecdh(
ephemeral_key.private,
recipient_public_key
)
# Derivar clave de cifrado
encryption_key = hkdf(
shared_secret,
salt=generate_random_salt(),
info=b"key-exchange",
length=32
)
# Cifrar clave a compartir
encrypted_key = aes_gcm_encrypt(
key_to_share,
encryption_key
)
# Firmar el paquete
signature = sign_data(
encrypted_key + ephemeral_key.public
)
return {
'encrypted_key': encrypted_key,
'ephemeral_public': ephemeral_key.public,
'signature': signature
}
4.3 Almacenamiento seguro
Opciones de almacenamiento por tipo:
Production Keys:
Location: HSM / AWS KMS
Access: Role-based + MFA
Backup: HSM cluster replication
Audit: Every access logged
Development Keys:
Location: HashiCorp Vault
Access: Developer role + approval
Backup: Encrypted in S3
Rotation: Monthly
Certificates:
Location: AWS Certificate Manager
Access: Service accounts only
Renewal: Auto (30 days before expiry)
Validation: DNS/Email
Secrets/Passwords:
Location: AWS Secrets Manager
Access: Application roles
Rotation: Every 90 days
Versioning: Last 5 versions
Protección en memoria:
// Protección contra memory dumps
void protect_key_in_memory(void *key, size_t key_len) {
// Marcar página como no-swappable
mlock(key, key_len);
// Marcar como solo lectura cuando no esté en uso
mprotect(key, key_len, PROT_READ);
// Limpiar después de uso
explicit_bzero(key, key_len);
// Liberar lock
munlock(key, key_len);
}
4.4 Uso de claves
Control de uso:
class KeyUsageController:
def __init__(self):
self.usage_limits = {
'encryption': 1000000, # Operations
'signing': 100000,
'time_limit': 365 * 24 * 3600 # Seconds
}
def authorize_key_use(self, key_id, operation):
# Verificar permisos
if not has_permission(current_user, key_id, operation):
raise PermissionError("Unauthorized key usage")
# Verificar límites
if exceeded_usage_limit(key_id):
trigger_key_rotation(key_id)
raise LimitExceeded("Key usage limit reached")
# Verificar propósito
if not matches_key_purpose(key_id, operation):
raise PurposeViolation("Key used for wrong purpose")
# Registrar uso
log_key_usage(key_id, operation, current_user)
return True
Separación de propósitos:
- Claves de cifrado NUNCA para firma
- Claves de producción NUNCA en desarrollo
- Claves de backup SOLO para recuperación
- Claves de usuario NUNCA para servicios
4.5 Rotación de claves
Calendario de rotación completo según ENS:
Tipo de clave | ENS Básico | ENS Medio | ENS Alto | Rotación forzada | Uso máximo |
---|---|---|---|---|---|
Master Keys (HSM) | 2 años | 1 año | 6 meses | Compromiso sospechado | N/A |
Key Encryption Keys (KEK) | 1 año | 6 meses | 3 meses | Límite de uso alcanzado | 100M operaciones |
Data Encryption Keys (DEK) | 6 meses | 90 días | 30 días | 1M de operaciones | 10M operaciones |
TLS Certificates | 1 año | 90 días | 90 días | Cambio de dominio | N/A |
Code Signing Certificates | 2 años | 1 año | 1 año | Compromiso de clave privada | N/A |
API Keys (Aplicación) | 6 meses | 90 días | 30 días | Empleado desvinculado | N/A |
Service Account Keys | 1 año | 6 meses | 90 días | Servicio descomisionado | N/A |
Database Encryption Keys | 6 meses | 3 meses | 1 mes | Brecha detectada | 50M transacciones |
SSH Keys (Admin) | 1 año | 6 meses | 3 meses | Acceso anómalo | N/A |
SSH Keys (Service) | 2 años | 1 año | 6 meses | Cambio de infraestructura | N/A |
Backup Encryption Keys | 1 año | 6 meses | 3 meses | Backup comprometido | N/A |
Rotación automatizada por tipo de clave:
class ENSKeyRotationScheduler:
"""
Planificador de rotación de claves según niveles ENS
"""
def __init__(self, ens_level: str):
self.ens_level = ens_level
self.rotation_schedules = self._load_ens_schedules()
self.emergency_triggers = self._load_emergency_triggers()
def create_rotation_schedule(self, key_inventory: list) -> dict:
"""
Crear calendario completo de rotación
"""
schedule = {
'daily': [],
'weekly': [],
'monthly': [],
'quarterly': [],
'annually': []
}
for key_info in key_inventory:
key_type = key_info['type']
creation_date = key_info['created']
# Obtener frecuencia según tipo y nivel ENS
rotation_freq = self.rotation_schedules[self.ens_level][key_type]
# Calcular próxima rotación
next_rotation = creation_date + rotation_freq
# Agregar buffer de seguridad (rotar 7 días antes)
next_rotation_safe = next_rotation - timedelta(days=7)
# Clasificar en cronograma
days_until = (next_rotation_safe - datetime.now()).days
if days_until <= 1:
schedule['daily'].append({
'key_id': key_info['id'],
'type': key_type,
'priority': 'urgent',
'deadline': next_rotation_safe
})
elif days_until <= 7:
schedule['weekly'].append({
'key_id': key_info['id'],
'type': key_type,
'priority': 'high',
'deadline': next_rotation_safe
})
elif days_until <= 30:
schedule['monthly'].append({
'key_id': key_info['id'],
'type': key_type,
'priority': 'medium',
'deadline': next_rotation_safe
})
elif days_until <= 90:
schedule['quarterly'].append({
'key_id': key_info['id'],
'type': key_type,
'priority': 'low',
'deadline': next_rotation_safe
})
else:
schedule['annually'].append({
'key_id': key_info['id'],
'type': key_type,
'priority': 'maintenance',
'deadline': next_rotation_safe
})
return schedule
def execute_scheduled_rotations(self, schedule_period: str) -> list:
"""
Ejecutar rotaciones programadas
"""
schedule = self.get_current_schedule()
rotations_to_execute = schedule.get(schedule_period, [])
results = []
for rotation in rotations_to_execute:
try:
# Validar prerrequisitos
self.validate_rotation_prerequisites(rotation['key_id'])
# Ejecutar rotación
result = self.execute_key_rotation(rotation)
# Validar post-rotación
self.validate_post_rotation(result['new_key_id'])
results.append({
'key_id': rotation['key_id'],
'status': 'success',
'new_key_id': result['new_key_id'],
'completion_time': datetime.now()
})
except Exception as e:
results.append({
'key_id': rotation['key_id'],
'status': 'failed',
'error': str(e),
'retry_scheduled': datetime.now() + timedelta(hours=4)
})
# Alertar al equipo de seguridad
self.alert_rotation_failure(rotation['key_id'], e)
# Generar informe de rotaciones
self.generate_rotation_report(results)
return results
Matriz de rotación de claves médicas:
Medical_Device_Key_Rotation:
Patient_Data_Keys:
rotation_frequency: "monthly"
pre_rotation_validation:
- patient_data_backup_verified
- clinical_workflow_coordination
- off_hours_scheduling
post_rotation_validation:
- data_accessibility_test
- clinical_system_integration_test
- performance_impact_assessment
AI_Model_Signing_Keys:
rotation_frequency: "annually"
regulatory_coordination:
- notify_competent_authorities: "30_days_prior"
- clinical_validation_required: true
- version_control_update: true
post_rotation_validation:
- model_signature_verification
- clinical_accuracy_validation
- regulatory_compliance_check
Device_Communication_Keys:
rotation_frequency: "quarterly"
deployment_strategy: "gradual_rollout"
rollback_capability: true
monitoring_period: "48_hours"
Proceso de rotación automatizada:
def rotate_key_automated(key_id):
try:
# 1. Generar nueva clave
new_key = generate_new_key(get_key_spec(key_id))
# 2. Fase de transición (ambas claves activas)
activate_key(new_key, mode='transition')
# 3. Re-cifrar datos gradualmente
schedule_reencryption_job({
'old_key': key_id,
'new_key': new_key.id,
'batch_size': 1000,
'priority': 'background'
})
# 4. Monitorear progreso
while not reencryption_complete():
time.sleep(300) # Check every 5 min
log_progress()
# 5. Desactivar clave antigua
deactivate_key(key_id)
# 6. Archivar para auditoría
archive_key(key_id, retention_years=7)
# 7. Notificar completación
notify_key_rotation_complete(key_id, new_key.id)
except Exception as e:
rollback_key_rotation(key_id)
alert_security_team(e)
raise
4.6 Destrucción de claves
Procedimiento de destrucción segura:
def secure_key_destruction(key_id):
# 1. Verificar que no hay datos dependientes
if has_dependent_data(key_id):
raise DependencyError("Cannot destroy key with dependent data")
# 2. Obtener aprobaciones necesarias
approvals = get_destruction_approvals(key_id)
if len(approvals) < 2:
raise ApprovalError("Insufficient approvals for destruction")
# 3. Backup final para cumplimiento
create_compliance_archive(key_id)
# 4. Destrucción criptográfica
# Sobrescribir múltiples veces
for i in range(7): # DoD 5220.22-M standard
overwrite_key_material(key_id, pattern=OVERWRITE_PATTERNS[i])
# 5. Eliminar de todos los sistemas
remove_from_hsm(key_id)
remove_from_kms(key_id)
remove_from_vault(key_id)
remove_from_backups(key_id)
# 6. Verificar destrucción
if key_still_exists(key_id):
raise DestructionError("Key destruction incomplete")
# 7. Certificado de destrucción
certificate = generate_destruction_certificate({
'key_id': key_id,
'timestamp': datetime.utcnow(),
'method': 'crypto_shredding',
'approvers': approvals,
'verified_by': current_user
})
# 8. Registro permanente
log_key_destruction(certificate)
return certificate
Controles de seguridad específicos
5.1 Segregación de funciones
Roles y responsabilidades:
Key_Administrator:
- Crear políticas de claves
- Aprobar generación de master keys
- Auditar uso de claves
- NO puede: Usar claves directamente
Key_Custodian:
- Generar claves operacionales
- Distribuir claves autorizadas
- Rotar claves según calendario
- NO puede: Modificar políticas
Key_User:
- Usar claves asignadas
- Solicitar nuevas claves
- Reportar incidentes
- NO puede: Compartir o exportar claves
Key_Auditor:
- Revisar logs de uso
- Verificar cumplimiento
- Investigar anomalías
- NO puede: Modificar claves o políticas
5.1bis Directrices de Uso de HSM según CCN-STIC-807
Configuración HSM para cumplimiento ENS:
HSM_Configuration_ENS:
Certification_Level: FIPS 140-2 Level 3 (mínimo)
Approved_Algorithms_Basic:
Symmetric:
- AES-256 (GCM, CBC)
- ChaCha20-Poly1305
Asymmetric:
- RSA-4096 (OAEP, PSS)
- ECDSA P-256, P-384
Hash:
- SHA-256, SHA-384, SHA-512
Approved_Algorithms_Medium:
Symmetric:
- AES-256 (GCM obligatorio)
Asymmetric:
- RSA-4096 (obligatorio)
- ECDSA P-384 (recomendado)
Hash:
- SHA-384 (mínimo)
Approved_Algorithms_High:
Symmetric:
- AES-256-GCM (obligatorio)
Asymmetric:
- RSA-4096 con OAEP SHA-384
- ECDSA P-521
Hash:
- SHA-512 (obligatorio)
Procedimientos HSM específicos para dispositivos médicos:
class MedicalDeviceHSMManager:
"""
Gestión especializada de HSM para dispositivos médicos
según IEC 62304 y MDR requisitos de ciberseguridad
"""
def __init__(self):
self.medical_key_policies = {
'patient_data_encryption': {
'algorithm': 'AES-256-GCM',
'key_derivation': 'HKDF-SHA384',
'rotation_frequency': timedelta(days=30),
'backup_requirement': 'geographic_redundancy',
'audit_level': 'detailed',
'fda_compliance': True
},
'diagnostic_algorithm_signing': {
'algorithm': 'ECDSA-P384',
'hash_function': 'SHA-384',
'rotation_frequency': timedelta(days=365),
'code_signing_cert': True,
'regulatory_approval': 'required_before_use'
},
'device_authentication': {
'algorithm': 'ECDSA-P256',
'certificate_validity': timedelta(days=730),
'mutual_tls': True,
'device_identity_binding': 'hardware_secure_element'
}
}
def generate_medical_device_key(self, purpose: str, device_class: str) -> dict:
"""
Genera claves específicas para dispositivos médicos
"""
if purpose not in self.medical_key_policies:
raise ValueError(f"Unknown medical purpose: {purpose}")
policy = self.medical_key_policies[purpose]
# Validar clasificación de dispositivo médico
if device_class in ['Class_IIa', 'Class_IIb', 'Class_III']:
# Requerir aprobación adicional para dispositivos de alto riesgo
if not self.validate_regulatory_approval(purpose, device_class):
raise ComplianceError("Regulatory approval required")
# Generar clave con parámetros específicos médicos
key_spec = {
'algorithm': policy['algorithm'],
'purpose': f"medical_{purpose}",
'device_class': device_class,
'regulatory_context': {
'mdr_compliance': True,
'fda_guidance': True,
'patient_safety': True
},
'key_attributes': {
'non_repudiation': True,
'key_recovery_escrow': device_class in ['Class_III'],
'audit_trail': 'comprehensive',
'geographic_restrictions': None # Global deployment
}
}
# Usar HSM dedicado para dispositivos médicos
medical_hsm = self.get_medical_hsm_partition()
key = medical_hsm.generate_key(key_spec)
# Registrar en inventario de dispositivos médicos
self.register_medical_key(key, device_class, purpose)
# Crear evidencias de cumplimiento
self.generate_compliance_evidence(key, device_class)
return key
def implement_medical_key_rotation(self, key_id: str, emergency: bool = False) -> dict:
"""
Rotación de claves para dispositivos médicos con consideraciones especiales
"""
key_info = self.get_medical_key_info(key_id)
# Validar impacto en dispositivos desplegados
deployed_devices = self.get_deployed_devices_using_key(key_id)
if len(deployed_devices) > 0 and not emergency:
# Planificar rotación gradual
rotation_plan = self.create_gradual_rotation_plan(deployed_devices)
# Notificar a autoridades regulatorias si es necesario
if self.requires_regulatory_notification(key_info):
self.notify_regulatory_authorities(key_id, rotation_plan)
# Coordinar con equipos clínicos
self.coordinate_clinical_rotation(rotation_plan)
# Ejecutar rotación
new_key = self.execute_medical_key_rotation(key_id, emergency)
# Validar que dispositivos funcionan con nueva clave
self.validate_post_rotation_functionality(deployed_devices, new_key)
# Documentar para auditorías regulatorias
self.document_medical_key_rotation(key_id, new_key, deployed_devices)
return new_key
Configuración de HSM por nivel de seguridad ENS:
HSM_Security_Levels:
Basic_Level:
hsm_partition: "legit-health-basic"
authentication: "password + smart_card"
key_backup: "encrypted_export"
audit_frequency: "monthly"
Medium_Level:
hsm_partition: "legit-health-medium"
authentication: "dual_authentication + biometric"
key_backup: "hsm_replication + encrypted_export"
audit_frequency: "weekly"
tamper_response: "immediate_zeroization"
High_Level:
hsm_partition: "legit-health-high"
authentication: "triple_authentication + biometric + pin"
key_backup: "hsm_cluster + geographic_redundancy"
audit_frequency: "daily"
tamper_response: "immediate_zeroization + alert"
physical_security: "24x7_monitoring + dual_custody"
network_isolation: "dedicated_vlan + firewall"
5.2 Control de acceso dual
Operaciones críticas con control dual:
- Generación de master keys
- Exportación de claves
- Destrucción de claves
- Cambio de políticas de seguridad
- Acceso a HSM físico
def dual_control_operation(operation, params):
# Solicitar primera autorización
auth1 = request_authorization(
user=params['initiator'],
operation=operation
)
# Solicitar segunda autorización (diferente persona)
auth2 = request_authorization(
user=params['approver'],
operation=operation,
exclude=[params['initiator']]
)
# Verificar ambas autorizaciones
if verify_dual_auth(auth1, auth2):
# Ejecutar con ventana de tiempo limitada
with time_limited_execution(minutes=30):
result = execute_operation(operation, params)
audit_dual_control(operation, auth1, auth2, result)
return result
else:
raise DualControlError("Dual authorization failed")
5.3 Escrow de claves
Procedimiento de escrow (solo claves críticas):
Key Escrow Process:
Eligible_Keys:
- Master encryption keys
- Disaster recovery keys
- Legal hold keys
Escrow_Method:
- Split: Shamir's Secret Sharing (3 of 5)
- Storage:
- Fragment 1: Bank safe deposit box
- Fragment 2: Legal firm
- Fragment 3: Executive safe
- Fragment 4: External auditor
- Fragment 5: Cloud backup (encrypted)
Recovery_Process:
- Requires: CEO + CFO + Legal approval
- Witnesses: External auditor
- Documentation: Notarized
- Verification: Multi-party video call
Protección física de material criptográfico
6.1 HSM físico
Physical Security:
Location: Secure datacenter cage
Access: Biometric + smartcard
Monitoring: 24/7 CCTV
Environmental:
- Temperature: 18-22°C
- Humidity: 45-55%
- Fire suppression: FM-200
Tamper_Protection:
- Mesh sensor
- Zeroization on tamper
- Audit log to remote system
6.2 Transporte de material criptográfico
Protocolo de transporte seguro:
- Doble contenedor sellado
- Courier bonificado con seguro
- Tracking GPS en tiempo real
- Verificación de integridad en destino
- Destrucción de contenedores usados
Gestión de certificados digitales
7.1 Infraestructura PKI
PKI Architecture:
Root_CA:
- Offline HSM
- 20 year validity
- RSA 4096 / ECC P-521
Intermediate_CA:
- Online HSM
- 10 year validity
- Issues end-entity certs
Certificate_Types:
- TLS/SSL: 90 days auto-renewal
- Code Signing: 1 year
- Email (S/MIME): 1 year
- Device: 2 years
- User Auth: 1 year
7.2 Ciclo de vida de certificados
class CertificateLifecycle:
def __init__(self):
self.renewal_threshold = 30 # days before expiry
def monitor_certificates(self):
for cert in get_all_certificates():
days_to_expiry = (cert.not_after - datetime.now()).days
if days_to_expiry < 0:
alert_expired_certificate(cert)
disable_certificate(cert)
elif days_to_expiry < self.renewal_threshold:
if cert.auto_renew:
self.auto_renew_certificate(cert)
else:
notify_manual_renewal_required(cert)
elif days_to_expiry < 60:
send_expiry_warning(cert)
def auto_renew_certificate(self, cert):
# Generar CSR
csr = generate_csr(cert.subject, cert.key_spec)
# Solicitar nuevo certificado
new_cert = ca.issue_certificate(csr)
# Instalar con overlap period
install_certificate(new_cert, overlap_days=7)
# Programar desactivación del antiguo
schedule_deactivation(cert, days=7)
Auditoría y cumplimiento
8.1 Registros de auditoría
Eventos registrados según ENS:
{
"timestamp": "2025-08-29T10:30:00Z",
"event_type": "KEY_GENERATION",
"key_id": "arn:aws:kms:key/12345",
"ens_classification": "MEDIO",
"algorithm": "AES-256-GCM",
"purpose": "patient_data_encryption",
"medical_context": {
"device_class": "Class_IIa",
"patient_impact": "direct",
"regulatory_requirement": "MDR_Article_17"
},
"requestor": {
"user_id": "admin@legithealth.com",
"role": "key_custodian",
"authentication_level": "mfa_biometric"
},
"approver": {
"user_id": "security@legithealth.com",
"role": "key_administrator",
"approval_method": "dual_control"
},
"source_context": {
"ip_address": "10.0.1.50",
"location": "Madrid_DC_Primary",
"session_id": "sess_abc123"
},
"hsm_details": {
"serial_number": "HSM-001",
"partition": "legit-health-medium",
"firmware_version": "7.4.2",
"fips_level": "Level_3"
},
"result": "SUCCESS",
"compliance_metadata": {
"ccn_stic_807_compliant": true,
"key_length": 256,
"expiry": "2025-11-29T10:30:00Z",
"rotation_schedule": "30_days",
"backup_created": true,
"escrow_required": false,
"audit_retention": "7_years"
},
"integration_references": {
"risk_assessment": "R-TF-013-002",
"threat_model": "T-024-006",
"ens_control": "OP.EXP.11"
}
}
Eventos adicionales para dispositivos médicos:
Medical_Device_Specific_Events:
CLINICAL_KEY_USAGE:
description: "Uso de claves en contexto clínico"
mandatory_fields:
- patient_anonymized_id
- clinical_procedure
- healthcare_provider
- diagnostic_accuracy_impact
REGULATORY_NOTIFICATION:
description: "Notificación a autoridades regulatorias"
mandatory_fields:
- competent_authority
- notification_type
- regulatory_deadline
- compliance_status
KEY_ESCROW_ACCESS:
description: "Acceso a claves en escrow"
mandatory_fields:
- legal_justification
- court_order_reference
- witness_list
- data_subjects_affected
8.1bis Inventario Completo de Claves Criptográficas
Template de inventario según RD 311/2022:
class ENSCryptographicInventory:
"""
Inventario completo de material criptográfico según ENS
"""
def generate_ens_inventory(self) -> dict:
"""
Genera inventario completo para auditoría ENS
"""
inventory = {
'metadata': {
'generation_date': datetime.now().isoformat(),
'ens_level': 'MEDIO',
'organization': 'Legit Health S.L.',
'system_category': 'Dispositivo Médico Clase IIa',
'audit_period': self.get_audit_period(),
'compliance_framework': ['ENS', 'MDR', 'ISO_27001']
},
'summary': {
'total_keys': 0,
'active_keys': 0,
'expired_keys': 0,
'keys_due_rotation': 0,
'hsm_keys': 0,
'software_keys': 0,
'compliance_score': 0.0
},
'key_categories': {},
'compliance_gaps': [],
'recommendations': []
}
# Obtener todas las claves por categoría
categories = [
'master_keys',
'patient_data_keys',
'ai_model_keys',
'communication_keys',
'backup_keys',
'administrative_keys'
]
for category in categories:
keys = self.get_keys_by_category(category)
inventory['key_categories'][category] = self.analyze_key_category(keys)
inventory['summary']['total_keys'] += len(keys)
# Evaluar cumplimiento
inventory['compliance_gaps'] = self.identify_compliance_gaps()
inventory['compliance_score'] = self.calculate_compliance_score()
inventory['recommendations'] = self.generate_recommendations()
return inventory
def analyze_key_category(self, keys: list) -> dict:
"""
Analiza una categoría específica de claves
"""
analysis = {
'count': len(keys),
'algorithms': {},
'key_strengths': {},
'rotation_status': {
'current': 0,
'due_soon': 0,
'overdue': 0
},
'storage_locations': {},
'compliance_issues': []
}
for key in keys:
# Algoritmos utilizados
algo = key.get('algorithm', 'unknown')
analysis['algorithms'][algo] = analysis['algorithms'].get(algo, 0) + 1
# Fortaleza de claves
strength = self.assess_key_strength(key)
analysis['key_strengths'][strength] = analysis['key_strengths'].get(strength, 0) + 1
# Estado de rotación
rotation_status = self.assess_rotation_status(key)
analysis['rotation_status'][rotation_status] += 1
# Ubicación de almacenamiento
location = key.get('storage_location', 'unknown')
analysis['storage_locations'][location] = analysis['storage_locations'].get(location, 0) + 1
# Identificar problemas de cumplimiento
issues = self.identify_key_compliance_issues(key)
analysis['compliance_issues'].extend(issues)
return analysis
Registro R-110-003 - Inventario de Claves Criptográficas:
# R-110-003 Inventario de Claves Criptográficas ENS
## Información General
- **Fecha de inventario**: 29 de agosto de 2025
- **Período de auditoría**: Q3 2025
- **Responsable**: Administrador de Claves ENS
- **Nivel de clasificación**: CONFIDENCIAL
## Resumen Ejecutivo
| Métrica | Valor | Estado |
| ------------------------------------ | --------- | ------ |
| Total de claves activas | 247 | ✅ |
| Claves próximas a rotación (30 días) | 12 | ⚠️ |
| Claves vencidas | 0 | ✅ |
| Cumplimiento CCN-STIC-807 | 98.8% | ✅ |
| Claves en HSM | 156 (63%) | ✅ |
| Algoritmos no aprobados | 0 | ✅ |
## Inventario por Categoría
### Claves Maestras (HSM)
| ID | Algoritmo | Creación | Próxima Rotación | Uso | Estado |
| ------ | --------- | ---------- | ---------------- | -------------- | ------ |
| MK-001 | AES-256 | 2025-01-15 | 2026-01-15 | KEK Generation | Activa |
| MK-002 | RSA-4096 | 2025-01-15 | 2026-01-15 | Cert Signing | Activa |
### Claves de Datos de Pacientes
| ID | Algoritmo | Propósito | Rotación | Datos Afectados | Estado |
| ------ | ----------- | --------------------- | ---------- | --------------- | ------ |
| PD-001 | AES-256-GCM | Historiales clínicos | 2025-09-29 | ~50K registros | Activa |
| PD-002 | AES-256-GCM | Imágenes diagnósticas | 2025-10-15 | ~200K imágenes | Activa |
### Claves de Modelos IA
| ID | Algoritmo | Modelo | Versión | Próxima Rotación | Estado |
| ------ | ---------- | -------------------- | ------- | ---------------- | ------ |
| AI-001 | ECDSA-P384 | Modelo Dermatológico | v2.1.5 | 2026-08-29 | Activa |
| AI-002 | ECDSA-P384 | Modelo Melanoma | v1.8.2 | 2026-08-29 | Activa |
8.2 Métricas de seguridad
Métrica | Objetivo | Actual | Estado |
---|---|---|---|
Claves rotadas a tiempo | 100% | 98% | ⚠️ |
Certificados expirados | 0 | 0 | ✅ |
Accesos no autorizados | 0 | 0 | ✅ |
Tiempo generación claves | <5s | 3.2s | ✅ |
Disponibilidad HSM | 99.99% | 99.95% | ✅ |
Claves sin uso >90 días | <5% | 8% | ⚠️ |
Respuesta a incidentes
9.1 Compromiso de claves
Procedimiento de respuesta inmediata:
def respond_to_key_compromise(compromised_key_id):
# 1. Revocación inmediata
revoke_key_immediately(compromised_key_id)
# 2. Notificación
alert_security_team("KEY_COMPROMISE", compromised_key_id)
# 3. Evaluación de impacto
affected_data = assess_impact(compromised_key_id)
# 4. Rotación de emergencia
new_key = emergency_key_rotation(compromised_key_id)
# 5. Re-cifrado de datos afectados
reencrypt_affected_data(affected_data, new_key)
# 6. Investigación forense
forensic_analysis = investigate_compromise(
key_id=compromised_key_id,
timeframe=last_7_days,
scope=['access_logs', 'network_traffic', 'system_logs']
)
# 7. Notificaciones regulatorias si necesario
if affects_personal_data(affected_data):
notify_dpa_within_72_hours()
if affects_medical_device(affected_data):
notify_competent_authority()
# 8. Documentación
create_incident_report({
'key_id': compromised_key_id,
'detection_time': datetime.utcnow(),
'impact': affected_data,
'response': new_key,
'forensics': forensic_analysis
})
Procedimientos operativos
10.1 Backup de claves
Backup Strategy:
Frequency: Daily incremental, Weekly full
Methods:
Primary: HSM cluster replication
Secondary: Encrypted export to cold storage
Tertiary: Paper backup (QR codes) in safe
Verification:
- Monthly restore test
- Quarterly full recovery drill
- Annual third-party audit
Storage_Locations:
- Online: Multi-region cloud
- Nearline: Local datacenter vault
- Offline: Bank safety deposit box
10.1bis Procedimientos de Recuperación de Claves
Procedimiento de escrow y recuperación según ENS:
class ENSKeyEscrowRecovery:
"""
Gestión de escrow y recuperación de claves según ENS
"""
def __init__(self):
self.escrow_threshold = 3 # Mínimo de 3 custodios para recuperación
self.authorized_custodians = self.load_authorized_custodians()
def create_key_escrow(self, key_id: str, criticality: str) -> dict:
"""
Crear escrow de clave usando Shamir's Secret Sharing
"""
if criticality not in ['critical', 'essential', 'important']:
raise ValueError("Invalid criticality level")
# Solo claves críticas y esenciales van a escrow
if criticality not in ['critical', 'essential']:
return {'escrow_required': False}
# Obtener clave del HSM
key_material = self.export_key_from_hsm(key_id)
# Configurar Shamir según criticidad
if criticality == 'critical':
threshold = 5 # Requiere 5 de 7 fragmentos
total_shares = 7
else: # essential
threshold = 3 # Requiere 3 de 5 fragmentos
total_shares = 5
# Generar fragmentos
shares = self.generate_shamir_shares(
key_material,
threshold,
total_shares
)
# Distribuir fragmentos a custodios
escrow_records = []
for i, share in enumerate(shares):
custodian = self.select_custodian_for_share(i, criticality)
# Cifrar fragmento con clave del custodio
encrypted_share = self.encrypt_share_for_custodian(share, custodian)
# Almacenar en ubicación segura
storage_location = self.store_encrypted_share(
encrypted_share,
custodian,
key_id
)
escrow_records.append({
'share_number': i + 1,
'custodian': custodian['name'],
'storage_location': storage_location,
'creation_date': datetime.now().isoformat(),
'verification_hash': self.calculate_share_hash(encrypted_share)
})
# Crear registro de escrow
escrow_record = {
'key_id': key_id,
'escrow_id': f"ESC-{key_id}-{int(time.time())}",
'criticality': criticality,
'threshold': threshold,
'total_shares': total_shares,
'shares': escrow_records,
'legal_authority': self.get_legal_authority_for_escrow(key_id),
'retention_period': '7_years',
'compliance_frameworks': ['ENS', 'MDR']
}
# Registrar en inventario de escrow
self.register_escrow_record(escrow_record)
# Generar certificado de escrow
self.generate_escrow_certificate(escrow_record)
return escrow_record
def recover_key_from_escrow(self, escrow_id: str,
authorization: dict) -> dict:
"""
Recuperar clave desde escrow con autorización múltiple
"""
# Validar autorización
if not self.validate_recovery_authorization(authorization):
raise SecurityException("Insufficient authorization for key recovery")
escrow_record = self.get_escrow_record(escrow_id)
# Recopilar fragmentos necesarios
required_shares = escrow_record['threshold']
available_custodians = self.get_available_custodians(escrow_record)
if len(available_custodians) < required_shares:
raise RecoveryException("Insufficient custodians available")
# Solicitar fragmentos a custodios
recovered_shares = []
for custodian in available_custodians[:required_shares]:
share = self.request_share_from_custodian(
custodian,
escrow_id,
authorization
)
# Verificar integridad del fragmento
if self.verify_share_integrity(share, custodian):
recovered_shares.append(share)
else:
raise IntegrityException(f"Share from {custodian} failed integrity check")
# Reconstruir clave usando Shamir
if len(recovered_shares) >= required_shares:
reconstructed_key = self.reconstruct_key_from_shares(recovered_shares)
# Importar clave a HSM
new_key_id = self.import_key_to_hsm(reconstructed_key)
# Registrar recuperación
self.log_key_recovery({
'original_key_id': escrow_record['key_id'],
'new_key_id': new_key_id,
'escrow_id': escrow_id,
'recovery_date': datetime.now().isoformat(),
'authorized_by': authorization['authorized_by'],
'custodians_involved': [c['name'] for c in available_custodians[:required_shares]],
'legal_basis': authorization.get('legal_basis', 'operational_recovery')
})
return {
'status': 'success',
'new_key_id': new_key_id,
'recovery_timestamp': datetime.now().isoformat()
}
else:
raise RecoveryException("Unable to recover sufficient shares")
10.2 Recuperación de desastres
Plan de recuperación de claves:
- Activar HSM de respaldo
- Restaurar master keys desde quórum
- Re-generar claves operacionales
- Verificar integridad de datos
- Restablecer servicios por prioridad
- Auditoría post-recuperación
Formación y concienciación
Programa de formación:
- Básico (todos): Importancia de protección de claves
- Intermedio (IT): Uso seguro de claves y certificados
- Avanzado (Security): Gestión de HSM y PKI
- Especializado (Key Custodians): Procedimientos de escrow y recuperación
Integración con otros controles ENS
- MP.SW.2: Claves para firma de código
- MP.COM: Certificados TLS/SSL
- MP.SI.2: Cifrado de soportes
- OP.ACC.5: Claves de autenticación fuerte
- OP.EXP.10: Firma de logs de auditoría
Documentación y registros
- T-024-018: Procedimiento completo de gestión
- T-024-019: Política de uso aprobada
- T-024-020: Inventario actualizado de claves
- R-110-003: Inventario de claves criptográficas ENS
- Registros de auditoría: Todos los eventos de claves
- Certificados de destrucción: Archivo permanente
- Informes de rotación: Evidencia de cumplimiento
- Certificados de escrow: Documentación legal de custodia
- Registros de recuperación: Evidencia de accesos a escrow
- Informes de cumplimiento CCN-STIC-807: Evaluaciones periódicas
Referencias cruzadas ENS e integración
14.1 Integración con otros controles ENS
Control ENS | Relación | Descripción de integración |
---|---|---|
OP.EXP.7 | Gestión de incidentes | Respuesta a compromiso de claves |
OP.EXP.10 | Registros de actividad | Firma criptográfica de logs |
OP.ACC.5 | Autenticación | Claves para MFA y certificados |
MP.COM.2 | Protección comunicaciones | Certificados TLS/SSL |
MP.SW.2 | Aceptación aplicaciones | Firma digital de código |
MP.SI.2 | Eliminación de soportes | Claves de cifrado de medios |
OP.CONT.2 | Plan de continuidad | Backup y recuperación de claves |
14.2 Referencias a documentación ENS
- T-110-007: Matriz RACI - Roles en gestión de claves
- T-110-008: CCN-CERT - Notificación de incidentes criptográficos
- ORG.1: Política de seguridad - Marco para políticas de claves
- OP.PL.1: Análisis de riesgos - Riesgos criptográficos
- OP.PL.2: Arquitectura de seguridad - Integración de HSM
14.3 Cumplimiento regulatorio médico
Medical_Compliance_Integration:
MDR_2017_745:
article_17: "Sistemas de gestión de calidad"
annex_I_17_2: "Medidas de seguridad IT"
implementation: "Claves para protección de datos clínicos"
IEC_62304:
section_5_5: "Integración e integración testing"
section_7: "Procesos de gestión de riesgos del software"
application: "Claves para firma de software médico"
ISO_14971:
clause_4_3: "Gestión de riesgos de dispositivos médicos"
clause_7: "Evaluación y control de riesgos"
integration: "Riesgos criptográficos en análisis general"
FDA_Cybersecurity_Guidance:
premarket: "Documentación de controles criptográficos"
postmarket: "Gestión de vulnerabilidades en algoritmos"
application: "Validación de implementación criptográfica"
Métricas de efectividad ENS
15.1 KPIs específicos de cumplimiento ENS
class ENSCryptographicMetrics:
"""
Métricas específicas de cumplimiento ENS para OP.EXP.11
"""
def calculate_ens_compliance_score(self) -> dict:
"""
Calcula puntuación de cumplimiento ENS
"""
metrics = {
'algorithm_compliance': self.check_algorithm_compliance(),
'key_length_compliance': self.check_key_length_compliance(),
'rotation_compliance': self.check_rotation_compliance(),
'hsm_usage_compliance': self.check_hsm_usage_compliance(),
'backup_compliance': self.check_backup_compliance(),
'audit_compliance': self.check_audit_compliance()
}
# Calcular puntuación ponderada
weights = {
'algorithm_compliance': 0.25,
'key_length_compliance': 0.20,
'rotation_compliance': 0.20,
'hsm_usage_compliance': 0.15,
'backup_compliance': 0.10,
'audit_compliance': 0.10
}
total_score = sum(metrics[key] * weights[key] for key in weights)
return {
'overall_score': total_score,
'individual_metrics': metrics,
'compliance_level': self.determine_compliance_level(total_score),
'areas_for_improvement': self.identify_improvement_areas(metrics)
}
15.2 Métricas operacionales
Métrica ENS | Objetivo | Medición | Responsable |
---|---|---|---|
Cumplimiento CCN-STIC-807 | 100% | Mensual | Key Administrator |
Rotación de claves en plazo | >98% | Automática | System |
Disponibilidad HSM | >99.9% | Continua | Infrastructure Team |
Tiempo de recuperación de escrow | <4 horas | Por evento | Security Team |
Auditorías de claves completadas | 100% | Trimestral | Compliance Team |
Certificados próximos a vencer | 0 | Diaria | Certificate Manager |
Incidentes criptográficos | 0 | Por evento | CISO |
Signature meaning
The signatures for the approval process of this document can be found in the verified commits at the repository for the QMS. As a reference, the team members who are expected to participate in this document and their roles in the approval process, as defined in Annex I Responsibility Matrix
of the GP-001
, are:
- Author: Team members involved
- Reviewer: JD-003, JD-004
- Approver: JD-001