Eran las 11 de la noche, había un incidente en producción, y yo estaba con tres terminales abiertas intentando recordar si era openssl x509 -text -noout -in cert.pem o openssl pkcs12 -info -in keystore.p12 -noout. El servidor tiraba TLS handshake failed y yo necesitaba confirmar en dos segundos si el certificado que habíamos desplegado era el correcto o si alguien había subido el de staging por error.
Ese momento de furia silenciosa donde querés pegar un grito pero son las 11 de la noche y tu familia está durmiendo — lo conocés, ¿no?
Ahí decidí que iba a construir algo para no volver a vivirlo.
Veintipico años mirando certificados en una terminal negra
Cuando empecé a administrar servidores en el hosting allá por 2007, los certificados SSL eran una rareza cara que solo las empresas grandes podían pagar. Yo los veía como objetos místicos: archivos binarios raros con extensiones que nadie sabía bien qué significaban — .pem, .der, .p12, .pfx, .crt, .cer. La misma cosa con seis nombres distintos dependiendo de quién los generó.
Aprendí a leerlos con openssl en la terminal como aprendí todo en esa época: rompiendo cosas en producción y rezando. Con el tiempo lo interioricé. Pero nunca dejó de ser un quilombo.
Después vino Let's Encrypt en 2015, los certificados se democratizaron, y de repente todos los proyectos tienen SSL. Renovaciones automáticas, cadenas de certificados, SANs con 40 dominios, keystores de Java para los proyectos enterprise con Spring Boot... El volumen de archivos de certificados que pasan por un workspace moderno es brutal.
Y cada vez que necesitás inspeccionar uno, la historia es la misma: salís de VS Code, abrís una terminal, tratás de recordar el comando, lo googleás si no te acordás, lo ejecutás, leés un wall of text que ocupa media pantalla, y cerrás la terminal. Flujo destruido.
El problema real no es el comando, es el contexto switching
Mirá esto. Cuando trabajás en una aplicación que consume servicios externos, validar los certificados es parte del ciclo de desarrollo normal. Estás configurando mutual TLS para conectarte a una API bancaria, o estás depurando por qué el cliente Java no confía en el certificado del servidor, o simplemente querés verificar que el .p12 que te mandó el equipo de seguridad tiene el CN correcto antes de meterlo en Kubernetes como un Secret.
El problema no es que openssl sea difícil. El problema es que te saca del contexto. Tenés el archivo ahí, en el explorador de VS Code, y para ver su contenido tenés que hacer un viaje de ida y vuelta a la terminal. Es como tener que salir a la calle para ver qué hay en la heladera.
Los archivos de imagen los podés previsualizar directamente. Los PDF también, con extensiones. Los SVGs se renderizan solos. ¿Por qué los certificados X.509 no?
Así nació gmm.certview
La idea era simple: doble click en un .pem y VS Code te muestra todo. Sin terminal. Sin recordar flags. Sin contexto switching.
El stack fue casi obvio para mí: TypeScript porque estoy en el ecosistema VS Code, y node-forge para el parsing criptográfico porque es la librería más completa y madura del ecosistema Node.js para manejar PKI. No quería depender de binarios externos ni de llamadas al sistema — necesitaba que todo funcionara 100% offline, en modo avión si hacía falta, y especialmente en ambientes corporativos donde instalarte cualquier cosa es un trámite de tres formularios y dos aprobaciones.
La pieza técnica más interesante fue el Custom Editor Provider de VS Code. En vez de registrar un comando que abrís manualmente, la extensión se registra como el editor nativo para ciertos tipos de archivo. VS Code le dice "oye, el usuario quiere abrir este .pem, ¿vos lo manejás?" y la extensión responde que sí y toma control.
// Así registrás un Custom Editor Provider en VS Code
// El 'viewType' tiene que matchear el que declarás en package.json
vscode.window.registerCustomEditorProvider(
'gmm.certview.editor', // identificador único de tu editor
new CertificateEditorProvider(context),
{
// Mantiene el webview en memoria aunque no sea la pestaña activa
// Importante para no re-parsear el cert cada vez que cambiás de tab
webviewOptions: { retainContextWhenHidden: true },
// Permite que múltiples tabs abran el mismo archivo
supportsMultipleEditorsPerDocument: false,
}
);
El provider recibe el contenido del archivo como Uint8Array y lo manda a node-forge para el parsing. Después renderiza todo en un Webview — básicamente una página HTML corriendo dentro de VS Code con acceso restringido al sistema.
Lo que ves cuando abrís un certificado
Abrís un .pem, .crt, .cer o .der y en vez del texto en base64 o el binario incomprensible, te aparece un panel con:
Subject e Issuer — quién es y quién lo firmó, con los campos del Distinguished Name bien separados (CN, O, OU, C, etc.) en vez del string gigante CN=api.empresa.com, O=Empresa S.A., C=AR.
Fechas de validez con alerta visual — esto fue lo primero que implementé porque es lo que más importa en un incidente. Verde si está vigente, amarillo si vence en menos de 30 días, rojo si ya expiró. Sin tener que calcular nada mentalmente.
// Lógica de alertas de vencimiento
// node-forge devuelve las fechas como objetos Date en cert.validity
function getCertificateStatus(notAfter: Date): 'valid' | 'expiring' | 'expired' {
const ahora = new Date();
const diasRestantes = Math.floor(
(notAfter.getTime() - ahora.getTime()) / (1000 * 60 * 60 * 24)
);
if (diasRestantes < 0) return 'expired'; // Rojo — ya expiró
if (diasRestantes <= 30) return 'expiring'; // Amarillo — ojo con esto
return 'valid'; // Verde — todo bien
}
Fingerprints SHA-1 y SHA-256 con un botón de copiar al portapapeles. Cuántas veces tuve que comparar fingerprints manualmente carácter por carácter en una terminal para verificar que dos certificados eran el mismo. Con el botón de copiar, lo pegás directo donde lo necesitás.
Clave pública — algoritmo (RSA, ECDSA, EdDSA) y tamaño en bits. Si alguien te manda un certificado RSA de 1024 bits en 2024, lo ves de entrada y mandás para atrás el pedido.
Extensiones X.509 y SANs — los Subject Alternative Names listados limpiamente. Cuándo un certificado dice que es válido para *.empresa.com y para empresa.com y para cuatro servicios internos más, lo ves de un vistazo.
Formatos soportados: no solo el .pem de toda la vida
Aquí es donde la cosa se pone buena para los que trabajan en ambientes enterprise.
PKCS#7 / .p7b — cadenas de certificados. Cada cert del bundle aparece en su propia pestaña dentro del panel. Muy útil para validar que la cadena está completa antes de configurar Nginx o un load balancer.
PKCS#12 / .p12 / .pfx — keystores con contraseña. La extensión te muestra un prompt, ingresás la password, y te abre el contenido: certificado, clave privada (muestra el tipo y tamaño, no el material de clave — no somos locos), y los certificados de la cadena. Esto en una terminal son tres comandos distintos con flags diferentes.
CSRs PKCS#10 — Certificate Signing Requests. Podés verificar que el CN y los SANs del CSR que estás a punto de mandar a la CA son los que querés antes de hacerlo.
CRLs — Certificate Revocation Lists. Menos común pero cuando lo necesitás, lo necesitás.
Panel sidebar del workspace — esto lo agregué después porque me di cuenta de que el problema no era solo abrir un cert individual. A veces querés ver todos los certificados del proyecto de una: cuál vence primero, si hay alguno ya expirado, etc. El sidebar escanea el workspace y lista todo con sus estados visuales.
Sin telemetría. En serio.
Esto lo digo explícitamente porque sé que importa. En ambientes corporativos financieros, de salud o gobierno, no podés usar extensiones que mandan datos a ningún lado. Los certificados son material criptográfico sensible — pueden ser certificados de producción, de servicios internos, de infraestructura crítica.
gmm.certview no manda ningún dato a ningún servidor. Todo el procesamiento ocurre localmente en tu máquina con node-forge. No hay analytics, no hay telemetría de uso, no hay nada. El código está disponible para auditar si tu equipo de seguridad lo requiere.
Funciona en modo avión. Funciona en redes corporativas con proxy restrictivo. Funciona en máquinas virtuales air-gapped. Si VS Code corre, la extensión funciona.
Instalación en dos clics
Podés instalar X509 Certificate Utility directo desde el marketplace:
https://marketplace.visualstudio.com/items?itemName=gmm.certview
O desde VS Code: Ctrl+P → ext install gmm.certview → Enter. Listo.
Después de instalar, hacé doble click en cualquier archivo .pem, .crt, .cer, .p12, .pfx, .p7b o .csr en el explorador de VS Code. Debería abrirse el viewer automáticamente. Si por algún motivo VS Code lo abre como texto, click derecho → "Reopen with" → "X509 Certificate Viewer".
Los errores que cometí en el camino
Error 1: subestimar los encodings. Pensé que todos los .pem eran iguales. No. Hay PEM con PKCS#1, PKCS#8, con headers específicos, con y sin bag attributes cuando vienen de un PKCS#12 exportado. Tuve que manejar cada variante por separado y agregar fallbacks. Si encontrás un archivo que no parsea bien, mandame el error (sin el cert, obvio) y lo agrego.
Error 2: el Webview y el Content Security Policy. VS Code tiene restricciones bastante estrictas sobre lo que podés hacer en un Webview. La primera versión tiraba errores de CSP en la consola de desarrollo. Tuve que revisar todos los estilos y scripts inline y mover todo a recursos locales con los URIs correctos usando webview.asWebviewUri().
Error 3: asumir que node-forge maneja todo. Para algunos casos edge de PKCS#12 con algoritmos más exóticos, node-forge tira excepciones crípticas. Tuve que agregar manejo de errores más granular y mensajes descriptivos para que el usuario entienda qué pasó en vez de ver "Error: invalid asn1 encoding".
Por qué existe el estándar X.509 y por qué es así de complicado
X.509 viene de 1988. Sí, 1988 — el año en que se publicó como parte del estándar X.500 de la ITU-T para directorios distribuidos. La Internet de hoy usa una versión evolucionada (v3, de 1996) con extensiones que se fueron agregando para soportar casos de uso que en 1988 nadie imaginaba: Subject Alternative Names para múltiples dominios, Extended Key Usage para distinguir certs de servidor de certs de código signing, OCSP para revocación en tiempo real.
La cantidad de formatos de archivo existe porque cada ecosistema fue haciendo lo suyo: OpenSSL popularizó el PEM (Privacy Enhanced Mail — sí, originalmente era para emails cifrados). Java usa JKS y PKCS#12. Windows usa PFX. Cada uno con sus propias convenciones.
Entender esto ayuda a entender por qué la herramienta tenía que soportar todos esos formatos. No es capricho, es la realidad de los proyectos modernos donde conviven stacks distintos.
Qué viene después
Hay algunas cosas en el roadmap que me tienen entusiasmado:
- Validación de cadena de confianza: dado un certificado de leaf y una CA bundle, verificar que la cadena es válida sin salir de VS Code.
- Comparación de certificados: seleccionar dos certs y ver las diferencias resaltadas. Muy útil para verificar rotaciones.
- Decodificación de campos OID desconocidos: hay extensiones X.509 propietarias de algunas CAs que node-forge no conoce. Quiero agregar una lookup table.
- Soporte para JKS de Java: técnicamente necesitaría re-implementar el formato JKS en TypeScript o usar una librería Java via WASM. Es el challenge más interesante que tengo por delante.
Si usás la extensión y tenés feedback, podés abrir un issue en el repo o contactarme directo. Los casos edge que más me interesan son los de ambientes enterprise con configuraciones raras — esos son los que hacen que la herramienta sea realmente robusta.
La próxima vez que estés en un incidente a las 11 de la noche tratando de recordar el comando de openssl, espero que puedas simplemente hacer doble click y seguir.
Instalala: marketplace.visualstudio.com/items?itemName=gmm.certview
Comentarios (0)
Deja un comentario
Artículos Relacionados
Harté de esperar que alguien maintuviera la extensión de HAProxy para VS Code — así que la hice yo
La única extensión de HAProxy para VS Code no la tocaban desde 2019. Todos los días la usaba en el trabajo y en mi homelab, y todos los días me tragaba errores de sintaxis sin ningún feedback. Un día dije basta y construí gmm-haproxy-vscode: LSP propio, autocompletado por sección, validación multi-versión y go-to-definition.
Vibe-coding vs stress-coding: cómo trabajo yo realmente con IA en proyectos que importan
El vibe-coding es fantástico hasta que el proyecto tiene usuarios reales. Acá la diferencia concreta entre cómo uso IA para experimentar y cómo la uso cuando hay producción de por medio.
Quantum computing para el dev web que no estudió física: ¿cuándo preocuparse en serio?
Un post de HN con 289 puntos sobre criptografía cuántica me dejó con una pregunta que no sé responder honestamente: ¿cuándo debería un full-stack developer empezar a preocuparse por SSL, hashing y tokens en un mundo post-cuántico? Acá intento traducirlo sin pretender ser experto.