recon_tls_sans
Extract Subject Alternative Names from TLS certificates to identify all domains secured by a certificate. Perform read-only TLS handshake analysis to discover certificate details including common name, issuer, validity, and SAN count.
Instructions
Extract Subject Alternative Names from the TLS certificate. Returns common_name, subject_alternative_names, issuer, validity, and san_count. Read-only TLS handshake.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| target | Yes | Target domain or IP:port, e.g. example.com or 1.2.3.4:443 |
Implementation Reference
- src/tools/recon.ts:216-272 (handler)Implementation of the "recon_tls_sans" tool in src/tools/recon.ts. It uses openssl to extract and parse Subject Alternative Names (SANs) and other certificate details from a target domain.
server.tool( "recon_tls_sans", "Extract Subject Alternative Names from the TLS certificate. Returns common_name, subject_alternative_names, issuer, validity, and san_count. Read-only TLS handshake.", { target: z .string() .describe("Target domain or IP:port, e.g. example.com or 1.2.3.4:443"), }, async ({ target }) => { const host = target.includes(":") ? target.split(":")[0] : target; const port = target.includes(":") ? target.split(":")[1] : "443"; const certInfo = await runShell( `echo | openssl s_client -servername ${host} -connect ${host}:${port} 2>/dev/null | openssl x509 -noout -text 2>/dev/null` ); // Parse SANs const sans: string[] = []; let cn = ""; let issuer = ""; let validity = ""; for (const rawLine of certInfo.stdout.split("\n")) { const line = rawLine.trim(); if (line.includes("DNS:")) { for (const part of line.split(",")) { const p = part.trim(); if (p.startsWith("DNS:")) { sans.push(p.slice(4)); } } } if (line.includes("Subject:") && line.includes("CN")) { const cnStart = line.indexOf("CN"); if (cnStart !== -1) { cn = line.slice(cnStart).split(",")[0].replace("CN = ", "").replace("CN=", ""); } } if (line.includes("Issuer:")) { issuer = line.replace("Issuer:", "").trim(); } if (line.includes("Not After")) { validity = line.trim(); } } const result = { common_name: cn, subject_alternative_names: sans, issuer: issuer.slice(0, 200), validity, san_count: sans.length, }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } ); - src/tools/recon.ts:216-272 (handler)The implementation of the `recon_tls_sans` tool handler in `src/tools/recon.ts`. It uses OpenSSL to retrieve certificate info and parses the Subject Alternative Names.
server.tool( "recon_tls_sans", "Extract Subject Alternative Names from the TLS certificate. Returns common_name, subject_alternative_names, issuer, validity, and san_count. Read-only TLS handshake.", { target: z .string() .describe("Target domain or IP:port, e.g. example.com or 1.2.3.4:443"), }, async ({ target }) => { const host = target.includes(":") ? target.split(":")[0] : target; const port = target.includes(":") ? target.split(":")[1] : "443"; const certInfo = await runShell( `echo | openssl s_client -servername ${host} -connect ${host}:${port} 2>/dev/null | openssl x509 -noout -text 2>/dev/null` ); // Parse SANs const sans: string[] = []; let cn = ""; let issuer = ""; let validity = ""; for (const rawLine of certInfo.stdout.split("\n")) { const line = rawLine.trim(); if (line.includes("DNS:")) { for (const part of line.split(",")) { const p = part.trim(); if (p.startsWith("DNS:")) { sans.push(p.slice(4)); } } } if (line.includes("Subject:") && line.includes("CN")) { const cnStart = line.indexOf("CN"); if (cnStart !== -1) { cn = line.slice(cnStart).split(",")[0].replace("CN = ", "").replace("CN=", ""); } } if (line.includes("Issuer:")) { issuer = line.replace("Issuer:", "").trim(); } if (line.includes("Not After")) { validity = line.trim(); } } const result = { common_name: cn, subject_alternative_names: sans, issuer: issuer.slice(0, 200), validity, san_count: sans.length, }; return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] }; } );