ScreenshotNeo

BlogEngineering

secp384r1: Security and TLS Elliptic Curve Support

Learn what secp384r1 (P-384) means in TLS, when it is required, how negotiation works, and how to configure and troubleshoot it.

By the ScreenshotNeo team1 October 20268 min read

secp384r1 is the TLS named group for the NIST P-384 elliptic curve. TLS 1.3 recognizes it with NamedGroup code point 0x0018. You can configure an implementation to offer P-384, but the protocol does not require every TLS implementation to support it. The peer, local policy, library version, and application configuration determine whether it is offered and whether it is selected.

Do not confuse a server’s ability to use P-384 with the curve actually chosen for a connection. In TLS 1.3, the key-exchange group and certificate signature algorithm are negotiated separately. A certificate using an ECDSA P-384 key does not prove that ephemeral key exchange used secp384r1.

What secp384r1 means

secp384r1, P-384, and NIST P-384 refer to the same standardized elliptic curve in the contexts covered here. TLS uses the name secp384r1 in its Supported Groups and KeyShare extensions. RFC 8446 lists it as a TLS 1.3 named group and assigns code point 0x0018 (RFC 8446).

Term Meaning
secp384r1 TLS/IANA name for the P-384 elliptic-curve group
P-384 NIST name commonly used in cryptographic libraries and policies
NamedGroup 0x0018 The TLS wire identifier for secp384r1
Supported Groups Groups an endpoint is willing and able to use
KeyShare Ephemeral key material sent for a proposed group in TLS 1.3

Is secp384r1 required by TLS?

No universal TLS requirement says every implementation must support secp384r1. The current TLS specification text in RFC 9846 states: “A TLS-compliant application MUST support key exchange with secp256r1 (NIST P-256) and SHOULD support key exchange with X25519.” That sentence mandates P-256 support and recommends X25519; it does not make P-384 mandatory.

Requirements can be stricter in a particular profile:

  • General TLS 1.3: P-384 is a recognized option, while P-256 is the expressly required baseline and X25519 is recommended by the cited specification.
  • NIST implementation guidance: NIST SP 800-52 Rev. 2 says that when elliptic-curve cipher suites are configured, an implementation shall support at least one of P-256 or P-384 (NIST SP 800-52 Rev. 2).
  • CNSA profile: RFC 9151 requires secp384r1 for CNSA TLS/DTLS connections (RFC 9151). This is a profile-specific policy, not a rule for all Internet TLS.

How TLS negotiates the group

  1. The client sends a Supported Groups list, such as X25519, secp256r1, and secp384r1.
  2. For TLS 1.3, the client may send one or more KeyShare entries containing ephemeral public keys for groups it prefers.
  3. The server selects a mutually supported group. If the needed key share was not sent, it can send a HelloRetryRequest asking for another one.
  4. The handshake continues with the selected group, subject to certificate and signature-algorithm checks negotiated independently.

A configured list is therefore only an offer or preference. The selected group depends on both peers and on policy. An endpoint can advertise P-384 yet negotiate X25519 on most connections if both sides prefer X25519.

Key exchange group versus certificate curve

TLS 1.3 separates the supported_groups/key_share decision from signature_algorithms. A certificate can contain an ECDSA P-384 public key while the handshake uses X25519 for ephemeral key exchange. Conversely, a connection can use secp384r1 for key exchange while the certificate signature uses another permitted algorithm. Inspect both parts of a handshake before drawing conclusions.

When should you enable P-384?

  • Enable it when an interoperability requirement, compliance profile, or peer requires P-384.
  • Offer it as an additional choice when your library supports it and you need a standards-recognized alternative to P-256 or X25519.
  • Keep a mutually supported fallback unless your policy explicitly forbids it.
  • Document the TLS library and version because defaults and enabled groups can change between releases.

Do not enable P-384 solely because a certificate uses P-384. That certificate fact does not identify the ephemeral key-exchange group.

Inspect and configure secp384r1 with OpenSSL

OpenSSL documents P-384 as a TLS 1.3 group and exposes APIs such as SSL_CTX_set1_groups() for setting the supported-group list. The API controls an application’s configuration; it does not guarantee that a peer will select P-384 (OpenSSL 3.5 group configuration documentation).

Check a server’s negotiated group

openssl s_client -connect example.com:443 -servername example.com -tls1_3 -groups X25519:secp384r1:secp256r1 -brief

Review the handshake output for the negotiated Server Temp Key or group field. This command constrains the client’s offered order; the result still depends on the server.

Offer only P-384 for a diagnostic handshake

openssl s_client -connect example.com:443 \
  -servername example.com \
  -tls1_3 \
  -groups secp384r1

If this fails while a normal handshake succeeds, the peer may not support P-384, may be applying a policy that excludes it, or may not have a compatible TLS 1.3 configuration.

Configure an OpenSSL application in C

#include <openssl/ssl.h>

SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
if (ctx == NULL) return 1;

/* Order is a preference; include fallbacks required by your policy. */
if (SSL_CTX_set1_groups_list(ctx, "X25519:secp384r1:secp256r1") != 1) {
    SSL_CTX_free(ctx);
    return 1;
}

/* Build the SSL object and perform the handshake... */

Use the API and option names documented for the OpenSSL version installed by your application. A library capability list is not the same as an application default.

Runnable client examples

Python

import socket
import ssl

host = "example.com"
context = ssl.create_default_context()
context.minimum_version = ssl.TLSVersion.TLSv1_3
context.set_ciphers("TLS_AES_256_GCM_SHA384:TLS_AES_128_GCM_SHA256")

with socket.create_connection((host, 443), timeout=10) as raw:
    with context.wrap_socket(raw, server_hostname=host) as tls:
        print("TLS version:", tls.version())
        print("cipher:", tls.cipher())
        print("peer certificate subject:", tls.getpeercert().get("subject"))

Python’s standard library does not expose a portable, cross-version setter for the TLS 1.3 supported-group order. Use the OpenSSL command line or the underlying library configuration when you must force a particular group.

Node.js

import tls from "node:tls";

const socket = tls.connect({
  host: "example.com",
  port: 443,
  servername: "example.com",
  minVersion: "TLSv1.3",
  /* OpenSSL group list; availability depends on the Node/OpenSSL build. */
  ecdhCurve: "X25519:P-384:P-256"
}, () => {
  console.log("TLS version:", socket.getProtocol());
  console.log("cipher:", socket.getCipher());
  console.log("authorized:", socket.authorized);
  socket.end();
});

socket.on("error", console.error);

Node passes curve configuration to its bundled OpenSSL. Verify the Node and OpenSSL versions in deployment before relying on a specific name or default.

cURL

curl --tlsv1.3 --curves X25519:secp384r1:secp256r1 https://example.com/ -v

Builds linked to different TLS backends may support different curve-option syntax. Use curl -V to identify the backend and check its documentation.

Or skip the browser setup

If you need rendered pages rather than a TLS diagnostic, ScreenshotNeo provides a website screenshot API. One GET request returns PNG, JPEG, WebP, or PDF. The API handles browser setup and rendering:

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' }); const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);

Before capture, cookie and consent banners are accepted and more than 60 known consent platforms, newsletter popups, and chat widgets are removed; each step can be disabled. Bot checks, blank pages, timeouts, failed loads, and cache hits are not billed, and response headers identify the page verdict and billing status. An MCP server provides take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. The Free plan includes 1,000 screenshots each month without a card; paid plans start at $5 for 3,000. See the ScreenshotNeo API documentation, then sign up for the free plan.

Troubleshooting

Symptom Likely cause Fix
Handshake fails when only secp384r1 is offered Peer lacks P-384 support or policy excludes it Offer a compatible fallback such as P-256 or X25519, or confirm the required profile.
P-384 is configured but another group is selected Peer preference, server policy, or key-share availability Inspect both sides’ Supported Groups and KeyShare data; configuration is not proof of selection.
Certificate inspection shows P-384, but handshake reports X25519 Certificate signature curve and ephemeral group are independent Inspect the TLS 1.3 key share and signature algorithm separately.
OpenSSL reports an unknown group Older library, different provider, or incorrect name Check openssl version, use the documented spelling secp384r1, and consult that release’s group list.
Node or cURL rejects the curve option Different TLS backend or bundled OpenSSL capability Run node -p process.versions or curl -V; use names supported by that build.
TLS 1.2 tests give confusing results TLS 1.2 cipher-suite and extension behavior differs from TLS 1.3 State the protocol version explicitly and analyze its supported groups and cipher suites separately.

Performance, reliability, and cost considerations

  • Performance: The cited standards and OpenSSL documentation do not provide a universal benchmark comparing P-384 with X25519 or P-256. Measure with your exact CPU, TLS library, connection pattern, and peer mix before changing defaults.
  • Reliability: Offering more than one mutually accepted group improves interoperability. Restricting a client to P-384 is useful for a policy test but can expose peers that do not support it.
  • Configuration drift: Record the TLS and OpenSSL versions and the effective group list. Package upgrades can change defaults.
  • Operational cost: A failed TLS handshake still consumes connection and diagnostic time. For rendered screenshots, ScreenshotNeo bills only clean shots; failed loads, bot checks, blank pages, timeouts, and cache hits are identified and not billed.

Checklist for a P-384 deployment

  • Identify the TLS version and applicable policy profile.
  • Confirm the library version supports secp384r1.
  • Set an explicit supported-group list when policy requires deterministic behavior.
  • Keep an approved fallback unless the profile forbids it.
  • Capture a handshake trace and verify the selected key-exchange group.
  • Inspect certificate signature algorithms independently.
  • Recheck configuration after library or operating-system upgrades.

FAQ

Is secp384r1 the same as P-384?

Yes. They are names for the same NIST P-384 curve in the TLS and cryptographic-library contexts described here.

Does using an ECDSA P-384 certificate force P-384 key exchange?

No. TLS 1.3 negotiates certificate signature algorithms separately from the ephemeral key-exchange group.

Should every public TLS server enable secp384r1?

There is no universal requirement to do so. Enable it when interoperability, policy, or a peer requires it, and validate the resulting negotiation.

Why might a CNSA deployment require P-384?

RFC 9151 defines CNSA-specific TLS/DTLS requirements that include secp384r1. That requirement applies to the profile’s scope.

Can I tell the selected group from a certificate alone?

No. Use handshake diagnostics that expose the TLS 1.3 key share or negotiated temporary key.