# Understanding the testssl.sh Rating System: How Grades Are Calculated and What They Mean

> Understand the testssl.sh rating system. Learn how protocol support, key exchange, and cipher strength determine grades from A to F for your SSL server.

- Repository: [Dirk Wetter/testssl.sh](https://github.com/drwetter/testssl.sh)
- Tags: deep-dive
- Published: 2026-03-01

---

**The testssl.sh rating system is an experimental implementation of the SSL Labs SSL Server Rating Guide that calculates a weighted score across protocol support (30%), key exchange (30%), and cipher strength (40%), then maps the result to letter grades A through F with possible caps for critical vulnerabilities or trust issues.**

The drwetter/testssl.sh repository includes an automated grading feature that benchmarks TLS/SSL configurations against industry standards. This testssl.sh rating system enables rapid comparative assessment of server security by assigning letter grades from A+ to F based on cryptographic strength, protocol versions, and certificate validity.

## How the testssl.sh Rating Algorithm Works

The rating logic is centralized in the `run_rating()` function within the main [`testssl.sh`](https://github.com/drwetter/testssl.sh/blob/main/testssl.sh) script (lines 24119–24130). This implementation follows the SSL Labs *SSL Server Rating Guide* (version 2009r, dated 2025‑05‑16) as specified in the project documentation.

### Initial Caps and Preconditions

Before calculating scores, the function checks for conditions that immediately limit the maximum possible grade:

- **STARTTLS penalty**: If the scan uses STARTTLS, the script applies an automatic **"T" cap** at lines 24131–24136 because STARTTLS is considered downgrade‑prone.
- **Hard caps**: If a cap of **F**, **T**, or **M** was previously set (e.g., due to Heartbleed, certificate name mismatches, or revoked certificates), the function exits early at lines 24153–24166, reporting a score of 0 with the capped grade.

## The Three Weighted Scoring Categories

When no hard cap exists, the algorithm evaluates three independent categories with specific weightings:

### Protocol Support (30% Weight)

The script inspects the best and worst supported TLS/SSL protocols using the `has_server_protocol` check (lines 24176–24202). Each protocol maps to a baseline score:

- **TLS 1.2 or 1.3**: 100 points
- **TLS 1.1**: 95 points  
- **TLS 1.0**: 90 points
- **SSL 3.0**: 80 points
- **SSL 2.0**: 0 points

The average of the best and worst protocol scores becomes *c1_score*, which is multiplied by 30% to produce *c1_wscore*.

### Key Exchange (30% Weight)

The rating system uses the pre‑computed `KEY_EXCH_SCORE` variable (lines 24111–24124) as *c2_score*. This score triggers automatic grade caps:

- **≤ 40 points**: Sets an **F** cap
- **≤ 80 points**: Sets a **B** cap

The weighted contribution is *c2_wscore = c2_score × 30%*.

### Cipher Strength (40% Weight)

This category analyzes the bit‑size of the strongest (`CIPH_STR_BEST`) and weakest (`CIPH_STR_WORST`) ciphers offered by the server (lines 24226–24253):

**Best cipher scoring:**
- ≥ 256 bits: 100 points
- ≥ 128 bits: 80 points  
- ≥ 0 bits: 20 points
- Else: 0 points

**Worst cipher scoring:**
- 0–127 bits: 20 points
- 128–255 bits: 80 points
- ≥ 256 bits: 100 points
- Else: 0 points

The average yields *c3_score*, weighted at 40% for *c3_wscore*.

## Calculating the Final Grade

### Score Aggregation

The script sums the three weighted contributions at lines 24266–24271:

```python
final_score = c1_wscore + c2_wscore + c3_wscore

```

If any category scored 0, the final score is forced to 0 regardless of other values.

### Grade Mapping Thresholds

The pre‑cap grade derives from the final score using these thresholds (lines 24276–24289):

| Final Score | Grade |
|-------------|-------|
| ≥ 80        | A     |
| ≥ 65        | B     |
| ≥ 50        | C     |
| ≥ 35        | D     |
| ≥ 20        | E     |
| < 20        | F     |

### Grade Cap Application

At lines 24291–24296, the script applies the **lowest** grade between the calculated pre‑cap grade and any existing `GRADE_CAP`:

- If the pre‑cap grade is **A** with **no warnings** and no caps exist, the output is **A+**
- If the pre‑cap grade is **A** but warnings exist, the output is **A-**
- Any active cap (F, T, or M) overrides higher grades

The final scores, grade, cap reasons, and warnings are written to JSON output via `fileout` calls (lines 24260–24274, 24300–24304).

## What Each Letter Grade Means

The testssl.sh rating system uses the following interpretations based on the SSL Labs specification:

- **A / A+**: Strong configuration with modern protocols (TLS 1.2/1.3), robust key exchange, and high‑strength ciphers. A+ indicates zero warnings.
- **B**: Minor weaknesses such as missing TLS 1.3 or marginal key‑exchange parameters triggering a B cap.
- **C**: Noticeable deficiencies including lack of TLS 1.2 support or equivalent issues.
- **D**: Significant protocol or cipher problems that reduce security margins substantially.
- **E**: Very weak configuration with multiple low‑strength ciphers or outdated protocols.
- **F**: Fatal security flaws including SSL v2/v3 support, Heartbleed vulnerability, or key‑exchange scores ≤ 40.
- **T**: Trust issue—typically indicates STARTTLS downgrade susceptibility, certificate chain problems, or revocation status.
- **M**: Name mismatch where the certificate subject does not match the scanned domain.

## Using the Rating System in Practice

### Run a Full Scan with Rating Output

By default, testssl.sh includes the rating in its standard output:

```bash
./testssl.sh https://example.com

```

Typical output format:

```text
 Rating (experimental) 
  Rating specs (not complete)  SSL Labs's 'SSL Server Rating Guide' (version 2009r from 2025-05-16)
  Protocol Support (weighted)  95 (28)
  Key Exchange (weighted)      80 (24)
  Cipher Strength (weighted)   90 (36)
  Final Score                  88
  Overall Grade                A

```

### Isolate Only the Rating Calculation

To skip all other checks and calculate only the grade:

```bash
./testssl.sh --rating-only https://example.com

```

### Disable Rating Completely

For scans where the grading system is not required:

```bash
./testssl.sh --disable-rating https://example.com

```

### Export Rating Data for CI Pipelines

Generate machine‑readable JSON output containing detailed scoring:

```bash
./testssl.sh -U --jsonfileout rating.json https://example.com

```

The resulting [`rating.json`](https://github.com/drwetter/testssl.sh/blob/main/rating.json) includes these fields:

```json
{
  "overall_grade": "A",
  "final_score": 88,
  "protocol_support_score": 95,
  "key_exchange_score": 80,
  "cipher_strength_score": 90,
  "rating_cap_reasons": [],
  "rating_warnings": []
}

```

## Summary

- The **testssl.sh rating system** implements the SSL Labs SSL Server Rating Guide (version 2009r) through the `run_rating()` function in [`testssl.sh`](https://github.com/drwetter/testssl.sh/blob/main/testssl.sh).
- **Three weighted categories** determine the score: Protocol Support (30%), Key Exchange (30%), and Cipher Strength (40%).
- **Grade caps** (F, T, M) immediately limit results based on critical vulnerabilities, trust issues, or STARTTLS usage.
- Final grades map to **A+ through F** based on score thresholds, with A+ reserved for perfect A‑grade scores with zero warnings.
- The system is **experimental** and intended for comparative benchmarking rather than formal security certification.

## Frequently Asked Questions

### How does testssl.sh calculate the difference between an A+ and A- grade?

According to the source code at lines 24291–24296, an **A+** requires a pre‑cap grade of A with **no warnings** and no active caps. If warnings exist (such as minor protocol deprecations) or any cap is present, the grade becomes **A-** instead.

### Why does my server get an automatic F grade even with strong ciphers?

The rating system applies **hard caps** that override calculated scores. If the scan detects SSL v2/v3 support, Heartbleed, or a key‑exchange score ≤ 40, the `GRADE_CAP` variable sets an **F** at lines 24153–24166, forcing the final output regardless of other category scores.

### What does the "T" cap mean in testssl.sh ratings?

The **T** cap indicates a trust or transport‑layer issue. The script automatically applies this cap (lines 24131–24136) when scanning STARTTLS services because they are considered downgrade‑prone. It also appears for certificate chain validation failures or revocation status problems.

### Can I rely on the testssl.sh rating for compliance reporting?

No. The documentation and source code explicitly label the rating system as **experimental**. While it follows the SSL Labs specification, it is designed for quick comparative assessments and diagnostics rather than formal security certification or compliance auditing.