Skip to content
ecdsa.com
C · Command line

LibreSSL

OpenBSD's LibreSSL, the 2014 fork of OpenSSL used by OpenBSD and macOS's system tools: the same DER ECDSA and key formats, Ed25519 but no Ed448, ML-KEM through its own API, no ML-DSA, and no RFC 6979.
License
OpenSSL AND ISC
Checked version
4.3.1 ·
Source
github.com/libressl/portable
Documentation
man.openbsd.org/

Compatibility at a glance

ECDSAEdDSAPost-quantum

ECDSA curves
P-224P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1
EdDSA
Ed25519
Public key formats
spki-pemspki-derx509
Private key formats
pkcs8-pempkcs8-derencrypted-pkcs8sec1-pemsec1-der

LibreSSL keeps OpenSSL's familiar libcrypto/libssl API and command line while removing legacy code, and adds its own libtls. macOS ships an older LibreSSL as its system crypto: on macOS 27.0.1, /usr/bin/openssl version printed LibreSSL 3.3.6 and ssh -V named the same library. The facts here were checked on the Alpine 3.24.2 package, LibreSSL 4.3.1 (upstream had reached 4.3.3), where the command is installed as libressl — scripts that call openssl fail there unless the compatibility package is added.

ECDSA behaves like OpenSSL's defaults: DER signatures, random nonces, no low-S normalization, and verification that accepts high-S. Unlike OpenSSL 3.2+, there is no deterministic RFC 6979 option. EVP_DigestVerify returned -1 for a raw r‖s signature, and the command line printed Error Verifying Data for it versus Verification Failure for a valid signature over other data — note the different capitalization from OpenSSL's messages, which breaks scripts that grep for the exact text.

Curves cover P-224 to P-521, secp256k1 and the Brainpool r1 curves; Ed25519 works through EVP_PKEY_ED25519, and there is no Ed448 at all. Key files interoperate with OpenSSL: SPKI and certificates for public keys, PKCS#8 (plain and encrypted) and SEC1 for private keys; ecparam -genkey writes SEC1 EC PRIVATE KEY, so convert with pkcs8 -topk8 when another tool wants PKCS#8, as the sample does.

Post-quantum support is partial: ML-KEM-768 and ML-KEM-1024 are available through LibreSSL's own MLKEM_* functions in <openssl/mlkem.h>, not through EVP or the command line, and ML-DSA does not exist (Algorithm ML-DSA-65 not found). Compare the algorithms in the post-quantum KEM playground; for signatures with ML-DSA use OpenSSL 3.5 or later.

Facts and the checks behind them

Nothing below is copied from documentation. The check content/libraries/verify/libressl/run.sh ran LibreSSL 4.3.1 in the container image alpine:3.24.2 on October 20, 2026; the page must match what it printed, and each fact lists those lines.

  • ECDSA signature encoding

    der

    EVP_DigestSign and libressl dgst -sign produce ASN.1 DER.

    Recorded by the check
    fact ecdsa-signature-encoding = der
  • ECDSA nonce

    random

    Random nonce: two signatures of the same message differ; there is no deterministic option.

    Recorded by the check
    fact ecdsa-nonce = random
  • Low-S when signing

    either

    s is not normalized: high-S values appeared among 64 signatures.

    Recorded by the check
    fact ecdsa-low-s-sign = either
  • High-S when verifying

    accepts-high-s

    A DER signature with s replaced by n − s verified.

    Recorded by the check
    fact ecdsa-low-s-verify = accepts-high-s
  • What the signing call hashes

    hashes-message-or-digest

    EVP_DigestSign hashes; ECDSA_sign signs a digest, and that signature verified against the message.

    Recorded by the check
    fact ecdsa-prehash = hashes-message-or-digest
  • Malformed ECDSA signature

    returns-error

    EVP_DigestVerify returned -1 for a raw r‖s signature and for a 3-byte blob.

    Recorded by the check
    fact ecdsa-malformed-signature = returns-error
    evidence ecdsa-malformed-signature: EVP_DigestVerify returned -1 for raw r||s and -1 for 3 bytes
  • Verification output on failure

    distinguishable

    dgst -verify printed Error Verifying Data for a non-DER signature and Verification Failure for a valid signature over other data.

    Recorded by the check
    fact cli-verify-output = distinguishable
    evidence cli-verify-output: valid: Verified OK; 64 zero bytes: Error Verifying Data; valid signature over other data: Verification Failure
  • ECDSA curves

    P-224P-256P-384P-521secp256k1brainpoolP256r1brainpoolP384r1brainpoolP512r1

    P-224, P-256, P-384, P-521, secp256k1 and brainpoolP256r1/P384r1/P512r1 signed and verified.

    Recorded by the check
    fact ecdsa-curves = P-224, P-256, P-384, P-521, secp256k1, brainpoolP256r1, brainpoolP384r1, brainpoolP512r1
  • EdDSA

    Ed25519

    Ed25519 through EVP_PKEY_ED25519; EVP_PKEY_ED448 is not defined.

    Recorded by the check
    fact eddsa = Ed25519
    evidence eddsa: EVP_PKEY_ED448 is not defined in the headers
  • Post-quantum algorithms

    ML-KEM

    ML-KEM-768 and ML-KEM-1024 round-tripped through the MLKEM_* API; genpkey -algorithm ML-DSA-65 failed with Algorithm ML-DSA-65 not found.

    Recorded by the check
    fact pqc = ML-KEM
    evidence pqc: ML-KEM rank 3: public key 1184 bytes, ciphertext 1088 bytes, round trip ok
    evidence pqc: ML-KEM rank 4: public key 1568 bytes, ciphertext 1568 bytes, round trip ok
    evidence pqc: genpkey -algorithm ML-DSA-65: Algorithm ML-DSA-65 not found
    evidence pqc: ML-KEM names in s_client help: none
  • Public key formats

    spki-pemspki-derx509

    SPKI PEM and DER and certificate public keys verified the same signature.

    Recorded by the check
    fact public-key-formats = spki-pem, spki-der, x509
  • Private key formats

    pkcs8-pempkcs8-derencrypted-pkcs8sec1-pemsec1-der

    PKCS#8 PEM and DER, encrypted PKCS#8 and SEC1 PEM and DER all signed; ecparam -genkey writes SEC1.

    Recorded by the check
    fact private-key-formats = pkcs8-pem, pkcs8-der, encrypted-pkcs8, sec1-pem, sec1-der
    evidence private-key-formats: genpkey -algorithm EC: works
    evidence private-key-formats: ecparam -genkey writes -----BEGIN EC PRIVATE KEY-----

Usage

Create a P-256 key with the libressl command, convert it to PKCS#8, sign and verify, and show that Ed25519 works while ML-DSA does not.
# Alpine and some distributions install LibreSSL's tool as "libressl", not "openssl".
L=libressl
$L ecparam -name prime256v1 -genkey -noout -out key.pem   # SEC1 "EC PRIVATE KEY"
$L pkcs8 -topk8 -nocrypt -in key.pem -out key.p8.pem       # PKCS#8 for other tools
$L pkey -in key.pem -pubout -out pub.pem

printf 'order #1042 approved' > msg.txt
$L dgst -sha256 -sign key.p8.pem -out sig.der msg.txt
$L dgst -sha256 -verify pub.pem -signature sig.der msg.txt

# Ed25519 works; ML-DSA does not exist in LibreSSL.
$L genpkey -algorithm ED25519 -out ed.pem && echo "Ed25519 key: $(head -1 ed.pem)"
$L genpkey -algorithm ML-DSA-65 2>&1 | grep -i "not found"

The snippet harness runs every sample verbatim in the container image alpine:3.24.2, and the run fails unless the output matches.

Setup
apk add --no-cache -q libressl=4.3.1-r0 >/dev/null
Command
OPENSSL_CONF=/dev/null sh usage.sh
Output must match (regular expression)
Verified OK\nEd25519 key: -----BEGIN PRIVATE KEY-----\nAlgorithm ML-DSA-65 not found

Libraries