TLS scanning¶
The network scanner connects to the hosts and ports you give it, performs a TLS handshake on each, and records the certificate the service presents along with how the service negotiates TLS. Its purpose is to find the certificates that exist on the network, including those PKIFactor did not issue.
Unknown certificates found by a scan go to the Discovery workspace, not to the CLM inventory. Nothing enters management until an administrator decides so.
Who can use it¶
| Role | Can |
|---|---|
| Administrator | Create, edit, start, stop and delete scans; take results under management |
| Auditor | Read scans, results and exports; no action |
The menu entry is in the Oversight workspace, Fleet monitoring > Network scanner. The scanner is a view of the whole network by nature: an auditor limited to some organizations does not see the entry, and the API refuses them (Vue globale réservée aux auditeurs de tout le parc).
Create a scan¶
- Open Fleet monitoring > Network scanner and click New Scan.
- Fill in the form.
- Click Create Scan. PKIFactor asks whether to start the scan now.
| Field | Content |
|---|---|
| Scan Name | Optional. Without a name the scan is called Scan <date> <time> |
| Description | Optional |
| Targets | One target per line: an IP address (198.51.100.5), a CIDR range (198.51.100.0/24) or a host name (mail.example.com). At most 100 lines. A range is expanded to all its host addresses; a range larger than 65,536 addresses (wider than a /16 in IPv4) is refused |
| Scan Type | The set of ports probed on every target (see below) |
| Port Range | Only with the Custom type: comma-separated ports and ranges, for example 443, 8443, 8080-8090 |
| Advanced Options > Connection Timeout (s) | Per connection, 5 seconds by default |
| Advanced Options > Max Concurrent | Number of probes run in parallel, 50 by default |
| Advanced Options > Observe SSH (port 22) | Also reads the SSH banner, host key and offered algorithms, without authenticating. Each probe appears in the target servers' logs |
| Schedule | Switch to run the scan automatically; see Schedule a scan |
A target that is neither a valid IP address, a CIDR range nor a host name is refused when you save, for example 198.51.100.0.24 typed instead of 198.51.100.0/24.
Scan types¶
| Type | Ports |
|---|---|
| Quick | 443, 8443 |
| Standard (default) | 443, 8443, 636, 993, 995, 465, 587, 25, 143, 110, 21, 389, 8080, 8444, 9443, 4443 |
| Deep | 1 to 10000 |
| Custom | The ports you enter in Port Range. If the field is empty or contains no valid port, the Standard set is used |
The card in the form describes Standard as "11 common ports"; the set actually has 16 ports since STARTTLS support was added (1.8.6).
The number of host and port combinations is capped at 50,000 per scan; beyond that the list is truncated. A Deep scan of a /24 range already reaches about 2.5 million combinations, so keep deep scans for a few hosts.
STARTTLS¶
Some services start in clear text and switch to TLS on request. Since version 1.8.6 the scanner speaks the protocol first, asks for TLS, and only then performs the handshake. The protocol is chosen from the port number:
| Port | Protocol | Command sent |
|---|---|---|
| 25, 587 | SMTP | EHLO pkifactor-scanner, then STARTTLS (only if the server advertises it) |
| 143 | IMAP | a1 STARTTLS |
| 110 | POP3 | STLS |
| 21 | FTP | AUTH TLS |
| 389 | LDAP | LDAPv3 StartTLS extended operation (OID 1.3.6.1.4.1.1466.20037) |
Results obtained this way are labelled STARTTLS-SMTP, STARTTLS-IMAP and so on; other results are labelled TLS.
Limits:
- The protocol is deduced from the port only. A mail server listening on a non-standard port is probed with a direct TLS handshake, which fails.
- Ports 465, 636, 993 and 995 use direct (implicit) TLS and are probed as such.
- No other STARTTLS protocol is supported (for example PostgreSQL, MySQL or XMPP).
- If the server refuses or does not offer STARTTLS, the port gives no result.
Status
STARTTLS was checked against real services when it was delivered: LDAP StartTLS on the lab's Active Directory, and SMTP on port 587 at Gmail and Office 365. IMAP, POP3 and FTP are covered by unit tests only.
What a scan collects¶
For every host and port that completes a TLS handshake:
| Data | Detail |
|---|---|
| Certificate | The end-entity certificate presented by the server, in PEM; subject, issuer, CN, subject alternative names (DNS and IP), serial number, validity dates, SHA-256 and SHA-1 fingerprints |
| Key | Algorithm and size: RSA (with size), ECC (named curve: P-256, P-384, P-521, secp256k1), Ed25519, Ed448, ML-DSA-44/65/87 |
| Signature | Signature algorithm, for example ECDSA-SHA256 |
| Negotiated TLS | Protocol version and cipher suite of the handshake |
| Minimum accepted TLS | The scanner retries with TLS 1.0, then 1.1, 1.2 and 1.3, each forced alone, and records the lowest version the service still accepts |
| Findings | See the table below |
Findings recorded on a result:
| Finding | Marks the result as weak |
|---|---|
| RSA key shorter than 2048 bits, or unknown key type | Yes |
| MD5 or SHA-1 signature | Yes |
| Negotiated version SSLv2, SSLv3, TLS 1.0 or TLS 1.1 | Yes |
| Service still accepts TLS 1.0 or TLS 1.1 (minimum accepted version) | Yes |
| Key vulnerable to a quantum computer (for example RSA 2048, ECC P-256) | No, informational |
| Validity longer than 398 days | No, informational |
What is not collected:
- The chain. Only the end-entity certificate is kept; intermediate certificates sent by the server are not stored.
- An audit of all accepted cipher suites. The cipher suite is the one negotiated in a single handshake.
The same certificate found on several hosts with the same port appears once in the scan's view, with the list of hosts where it was seen.
Each TLS port that answers receives several connections (the main handshake, a handshake through openssl s_client, and up to four handshakes to find the minimum version). Warn the teams that run intrusion detection before scanning their networks.
Results¶
Click a scan in the list to open its detail page. During a run the page shows a progress bar; results appear when the scan completes.
The detail page shows:
- counters: Hosts Scanned, Certificates Found, Scan Type, Status;
- a breakdown of the scan's certificates (state, expiry, algorithms, issuing authorities, TLS versions);
- the Scan Results table: Host:Port, CN, Issuer, Algorithm, TLS (with Min TLS and a warning when the service still accepts an old version), Expires, Issues, and State / Action;
- filters (All, Weak, OK, With issues, No issues) and a text filter;
- with the SSH option, an SSH observations table: banner, host key, offered key exchange, weaknesses (weak key exchange, CBC or RC4 ciphers, MD5 or SHA-1 MACs, DSA, RSA host key under 2048 bits) and whether a post-quantum key exchange is offered.
Export CSV and Export JSON download the TLS results. The CSV columns are: Host, Port, TLS Version, Min TLS, Cipher Suite, CN, Issuer, Serial, Expires, Algorithm, Key Size, Self-Signed, Weak, Vulnerabilities, Quantum Risk.
Running a scan again (Re-run) replaces its previous results: a scan keeps only its latest run.
State of each result¶
| State | Meaning |
|---|---|
| Managed | The certificate's SHA-256 fingerprint matches a certificate already recorded in PKIFactor, other than one recorded by a scan (see the note below) |
| At risk | Not matched, and weak (see the findings above), self-signed, or expiring within 30 days |
| Unmanaged | Not matched, and none of the above |
Two definitions of managed
On the scan detail page, a certificate imported from a file or absorbed from a CA connector counts as Managed. In the Discovery workspace, the same certificate is outside the CLM inventory until someone takes it under management. Use the Discovery workspace to decide what is really managed.
Renew from a profile¶
From the detail page an administrator can replace a discovered certificate with one issued by PKIFactor:
- Click Renew on a row, select several rows and click Renew the selection, or use Renew all on the At risk or Unmanaged group.
- In the Renew from a profile window, choose the Issuance profile.
- With a single endpoint the Common name (CN) and SANs can be edited. Factory names such as
localhostare refused: enter the real service name. In a bulk renewal, rows with a factory name are skipped. - Preview shows what will be requested; Renew sends one request per endpoint through the normal issuance path (the profile's approval rules apply).
Important points:
- This issues a new certificate. Installing it on the endpoint is up to you, or to a deployment target if the device is managed.
- The request is made with an RSA 2048-bit key. A profile that does not allow RSA 2048 refuses it.
- To bring the existing certificate under management without reissuing it, use Take under management in the Discovery workspace.
Schedule a scan¶
In the scan form, turn on Schedule and choose a Preset or type a Cron Expression (minute hour day month weekday):
| Preset | Cron expression |
|---|---|
| Daily (2 AM) | 0 2 * * * |
| Weekly (Mon 3 AM) | 0 3 * * 1 |
| Monthly (1st 4 AM) | 0 4 1 * * |
| Custom | Your own expression |
Times are in UTC. PKIFactor checks every minute for scans that are due and starts them in the background; the next run is computed after each run, including after a failure. A scheduled scan registers new certificates in the Discovery workspace exactly like a manual scan, without duplicates.
A scan that was running when the backend restarted is marked Stopped at the next start.
Limits and protections¶
- No address filtering. The scanner does not block private, loopback or link-local addresses: it is designed to explore internal networks. Only administrators can create or start a scan; auditors can only read.
- Size limits. 100 target lines per scan, 65,536 addresses per range, 50,000 host and port combinations per run.
- Connections from the backend. Probes leave from the backend container. The firewall must allow it to reach the scanned ports; see Network flows.
- Not in the audit trail. Creating, starting or stopping a scan is written to the application log, not to the audit trail. Certificates issued through Renew from a profile are audited like any other issuance.
Troubleshooting¶
| Symptom | Cause and fix |
|---|---|
| Invalid target(s): ... when saving | A line is not an IP address, CIDR range or host name; correct the typo (/24, not .24). (> 65536 adresses) after a range: the range is too large, split it into /16 or smaller ranges |
| Max 100 target entries | Split the list into several scans, or use CIDR ranges |
| Scan is already running | Wait for the end of the run or click Stop |
| Stop the scan before deleting | Stop the scan, then delete it |
| Scan finished with no result | Ports filtered between the backend and the targets, wrong scan type, or a STARTTLS service on a non-standard port |
| A mail or LDAP server is missing from the results | The server does not offer STARTTLS on its standard port, or listens on another port (only the ports in the STARTTLS table are negotiated) |
| Scan Failed with Scan execution failed. Check server logs. | Read the backend log (NETWORK_SCAN_*, SCAN_JOB_FAILED events) |
| The results of the previous run disappeared | Expected: Re-run replaces the results of the scan. Create a separate scan to keep both |
Via the API
# Sign in
curl -s -c jar -X POST https://clm.example.com/api/auth/login \
--data-urlencode "email=admin@example.com" --data-urlencode "password=$PASSWORD"
# Create a scheduled scan (JSON); the response gives its id
curl -s -b jar -X POST https://clm.example.com/api/scans \
-H "Content-Type: application/json" \
-d '{"name": "Mail servers", "targets": ["198.51.100.16/28", "mail.example.com"],
"scan_type": "standard", "scan_options": {"timeout": 5, "max_concurrent": 50},
"schedule_enabled": true, "schedule_cron": "0 2 * * *"}'
curl -s -b jar -X POST https://clm.example.com/api/scans/7/start # start now
curl -s -b jar https://clm.example.com/api/scans/7 # status and progress
curl -s -b jar "https://clm.example.com/api/scans/7/results?is_weak=true&per_page=200"
curl -s -b jar -o scan7.csv "https://clm.example.com/api/scans/7/export?format=csv"
curl -s -b jar -X POST https://clm.example.com/api/scans/7/stop
"scan_type": "custom", "port_range": "443,8000-8100". For SSH observation add "ssh": true to scan_options. All routes are in /api/v1/docs, tag network-scanner.