# Codex — Actualización de seguridad Alexa: Signature-256 / SHA-256

## Proyecto

Trabajar exclusivamente sobre:

```text
C:\xampp\htdocs\radio-babasonica-alexa\
```

Proyecto actual:

```text
Skill Radio Babasónica v0.1
```

Endpoint público actual:

```text
https://aproposito.ddns.net/radio-babasonica-alexa/public/
```

Stream:

```text
https://aproposito.ddns.net/live/radiobbs/index.m3u8
```

---

# Objetivo

Actualizar la validación criptográfica de requests de Alexa para que use como mecanismo principal:

```text
Signature-256
SHA-256
```

y dejar, sólo si resulta razonable para compatibilidad:

```text
Signature
SHA-1
```

como fallback secundario.

La implementación actual reportó:

```text
SignatureCertChainUrl
Signature
SHA-1
```

El objetivo es modernizarla antes de conectar la Skill con Alexa Developer Console.

---

# Restricciones obligatorias

NO modificar:

```text
SignalLive
MediaMTX
mediamtx.yml
FFmpeg
radiobbs
Apache VirtualHosts
/live/
WordPress
app C#
Skill del Mundial
```

NO reiniciar servicios.

NO desactivar validaciones de seguridad.

NO inventar Skill ID.

NO configurar todavía Alexa Developer Console.

NO incluir secretos, tokens, claves privadas, cookies o headers sensibles completos en logs o reportes.

---

# Paso 1 — Inspeccionar implementación actual

Revisar especialmente:

```text
C:\xampp\htdocs\radio-babasonica-alexa\src\AlexaRequestVerifier.php
C:\xampp\htdocs\radio-babasonica-alexa\src\AlexaRequestHandler.php
C:\xampp\htdocs\radio-babasonica-alexa\public\index.php
C:\xampp\htdocs\radio-babasonica-alexa\src\bootstrap.php
C:\xampp\htdocs\radio-babasonica-alexa\README.md
```

Identificar:

```text
cómo obtiene SignatureCertChainUrl
cómo obtiene Signature
cómo verifica la firma
qué algoritmo OpenSSL usa
cómo reporta errores
cómo hace logging
```

Registrar lo encontrado.

---

# Paso 2 — Implementar Signature-256 como primera opción

La nueva lógica debe ser:

```text
1. Buscar header Signature-256
2. Si existe:
      verificar el body usando SHA-256
3. Si no existe:
      opcionalmente buscar Signature
4. Si existe Signature:
      verificar con SHA-1 como fallback de compatibilidad
5. Si no existe ninguna firma aceptable:
      rechazar la request
```

Preferencia obligatoria:

```text
Signature-256 > Signature
```

No usar SHA-1 si `Signature-256` está presente.

Si `Signature-256` existe pero falla:

```text
NO hacer fallback automático a Signature
```

La petición debe rechazarse.

Motivo:

```text
evitar downgrade silencioso
```

---

# Paso 3 — Headers HTTP

Recordar que PHP/Apache puede exponer los headers con distintos nombres/casing.

La implementación debe poder obtener correctamente:

```text
Signature-256
Signature
SignatureCertChainUrl
```

sin depender del casing original.

Por ejemplo, considerar que PHP puede presentar:

```text
HTTP_SIGNATURE_256
HTTP_SIGNATURE
HTTP_SIGNATURECERTCHAINURL
```

o mecanismos equivalentes.

Usar una función centralizada para obtener headers si ayuda a evitar duplicación.

---

# Paso 4 — Verificación OpenSSL

Para `Signature-256`, verificar el cuerpo RAW exacto recibido.

Algoritmo esperado:

```text
SHA-256
```

En PHP/OpenSSL usar la constante o mecanismo apropiado, por ejemplo conceptualmente:

```php
OPENSSL_ALGO_SHA256
```

Para fallback clásico `Signature`, usar:

```text
SHA-1
```

sólo si:

```text
Signature-256 NO viene presente
```

y sólo como fallback explícito.

No alterar el body antes de verificarlo.

No re-serializar JSON.

Verificar exactamente los bytes recibidos.

---

# Paso 5 — Mantener intactas las demás validaciones

NO debilitar ni eliminar:

```text
SignatureCertChainUrl validation
HTTPS obligatorio
host permitido
path permitido
puerto 443
certificado X.509
vigencia del certificado
SAN echo-api.amazon.com
timestamp <= 150 segundos
applicationId / ALEXA_SKILL_ID
```

Si detectas que alguna validación actual está incorrecta, documentarlo.

No cambiarla silenciosamente salvo que sea necesario para corregir un bug evidente y bien fundamentado.

---

# Paso 6 — Comportamiento esperado

## Caso A

Headers:

```text
Signature-256: presente y válida
Signature: ausente
```

Resultado:

```text
ACEPTAR
algoritmo usado: SHA-256
```

## Caso B

Headers:

```text
Signature-256: presente y válida
Signature: presente
```

Resultado:

```text
ACEPTAR
algoritmo usado: SHA-256
```

No verificar SHA-1 adicionalmente.

## Caso C

Headers:

```text
Signature-256: presente pero inválida
Signature: presente y aparentemente válida
```

Resultado:

```text
RECHAZAR
```

No permitir downgrade.

## Caso D

Headers:

```text
Signature-256: ausente
Signature: presente y válida
```

Resultado:

```text
ACEPTAR mediante fallback SHA-1
```

si decides conservar compatibilidad.

## Caso E

Headers:

```text
Signature-256: ausente
Signature: ausente
```

Resultado:

```text
RECHAZAR
```

---

# Paso 7 — Logging

Actualizar logging de seguridad para poder registrar únicamente:

```text
signature_algorithm=sha256
```

o:

```text
signature_algorithm=sha1-fallback
```

NO registrar:

```text
Signature-256 completo
Signature completo
certificado completo
body completo
tokens
```

En errores, se puede registrar:

```text
signature_verification_failed
signature_header_missing
signature_algorithm
requestId
timestamp
```

si están disponibles.

---

# Paso 8 — Pruebas unitarias / locales

Agregar pruebas específicas para la lógica de selección de algoritmo.

No hace falta falsificar una request completa de Alexa si resulta impráctico.

Separar, si hace falta, la lógica:

```text
selección de header
selección de algoritmo
verificación criptográfica
```

para poder probarla con claves/certificados de prueba locales.

Crear pruebas al menos para:

```text
Signature-256 válida
Signature-256 inválida
Signature-256 válida + Signature presente
Signature-256 inválida + Signature válida => debe fallar
sólo Signature válida => fallback
sin firmas => rechazo
```

NO usar certificados privados reales de Amazon.

Se pueden generar claves de prueba locales exclusivamente dentro de tests.

Si se generan archivos temporales, eliminarlos al terminar o mantenerlos sólo dentro de:

```text
tests/
```

sin secretos reales.

---

# Paso 9 — Mantener pruebas existentes

Ejecutar nuevamente:

```text
tests/run.php
```

y todos los tests existentes.

Confirmar que sigan pasando:

```text
LaunchRequest
PlayRadioIntent
PauseIntent
ResumeIntent
StopIntent
PlaybackStarted
PlaybackStopped
PlaybackFailed
PlaybackController Play
PlaybackController Pause
JSON inválido
```

---

# Paso 10 — PHP lint

Ejecutar `php -l` sobre todos los PHP del proyecto:

```text
public\
src\
config\
tests\
```

Ningún archivo debe presentar errores de sintaxis.

---

# Paso 11 — Endpoint público

NO cambiar la URL:

```text
https://aproposito.ddns.net/radio-babasonica-alexa/public/
```

Verificar únicamente que:

```text
GET => 405
POST inválido => respuesta controlada
Content-Type => application/json
HTTPS => OK
```

No intentar superar la validación Alexa con requests falsas en producción.

---

# Paso 12 — README

Actualizar `README.md` para documentar:

```text
Signature-256 / SHA-256 es el mecanismo principal
Signature / SHA-1 queda sólo como fallback si se conserva
no se hace downgrade si Signature-256 está presente y falla
```

Agregar también cómo identificar en logs qué algoritmo fue usado.

---

# Paso 13 — Reporte obligatorio

Generar:

```text
C:\xampp\htdocs\radio-babasonica-alexa\RADIO_BABASONICA_ALEXA_SIGNATURE256_RESULTS.md
```

Debe contener:

# Radio Babasónica — Signature-256 Results

## Resumen

```text
Actualización completada: SI / PARCIAL / NO
Signature-256 implementado: SI / NO
SHA-256 implementado: SI / NO
Fallback Signature/SHA-1: SI / NO
Downgrade bloqueado: SI / NO
Tests generales: PASS / FAIL
Tests Signature-256: PASS / FAIL
PHP lint: PASS / FAIL
Endpoint público sin cambios: SI / NO
```

## Archivos modificados

Lista exacta.

## Archivos creados

Lista exacta.

## Lógica final

Explicar con un diagrama, por ejemplo:

```text
Request Alexa
   |
   +-- Signature-256 presente?
   |       |
   |       +-- SI --> SHA-256 --> válida? --> aceptar
   |                           \
   |                            --> inválida --> rechazar
   |
   +-- NO --> Signature presente?
           |
           +-- SI --> SHA-1 fallback --> válida? --> aceptar/rechazar
           |
           +-- NO --> rechazar
```

## Código relevante

Mostrar sólo fragmentos mínimos necesarios de:

```text
selección de header
selección del algoritmo
openssl_verify
```

No pegar archivos completos.

## Pruebas Signature-256

Tabla:

| Caso | Esperado | Resultado |
|---|---|---|
| Signature-256 válida | aceptar SHA-256 | |
| Signature-256 inválida | rechazar | |
| Signature-256 + Signature | usar SHA-256 | |
| Signature-256 inválida + Signature válida | rechazar, sin downgrade | |
| sólo Signature válida | fallback SHA-1 | |
| sin firmas | rechazar | |

## Pruebas de regresión

Tabla con los tests existentes.

## PHP lint

Resultado.

## Endpoint

Confirmar:

```text
https://aproposito.ddns.net/radio-babasonica-alexa/public/
```

sigue operativo.

## Seguridad

Confirmar que siguen activas:

```text
validación certificado
validación SAN
validación timestamp
validación Skill ID
sanitización logs
```

## Pendientes

Dejar explícito:

```text
Skill ID real aún no configurado
Prueba real Alexa aún no ejecutada
Developer Console aún no configurada
Echo físico aún no probado
```

---

# Criterios de aceptación

```text
[ ] Signature-256 tiene prioridad
[ ] Signature-256 usa SHA-256
[ ] Signature usa SHA-1 sólo como fallback opcional
[ ] No hay downgrade si Signature-256 está presente y falla
[ ] Body RAW se verifica sin modificar
[ ] Certificado sigue validándose
[ ] Timestamp sigue validándose
[ ] Skill ID sigue validándose
[ ] Logs no exponen firmas
[ ] Tests Signature-256 pasan
[ ] Tests anteriores siguen pasando
[ ] PHP lint pasa
[ ] Endpoint HTTPS no cambió
[ ] No se modificó MediaMTX
[ ] No se modificó radiobbs
[ ] No se reinició ningún servicio
[ ] Reporte final generado
```

---

# Importante

Esta tarea es exclusivamente una actualización de seguridad del backend.

Al finalizar NO crear la Skill todavía.

NO pedir al usuario que configure Amazon desde Codex.

Primero generar:

```text
RADIO_BABASONICA_ALEXA_SIGNATURE256_RESULTS.md
```

y ese archivo será revisado por ChatGPT antes de pasar a Alexa Developer Console.
