Skip to content
ecdsa.com
C

wolfSSL (wolfCrypt)

wolfSSL's embedded TLS and wolfCrypt library: DER ECDSA over a digest you supply, with a verify call whose return code and verdict are separate — and a feature set that depends entirely on how it was built.
License
GPL-3.0-only
Checked version
5.9.4 ·
Source
github.com/wolfSSL/wolfssl
Documentation
www.wolfssl.com/documentation/manuals/wolfssl/

Compatibility at a glance

ECDSAEdDSAPost-quantum

ECDSA curves
P-224P-256P-384P-521
EdDSA
Ed25519

wolfSSL targets embedded systems and FIPS deployments, and almost everything is a compile-time option: curves, EdDSA variants, deterministic nonces, post-quantum algorithms and PEM support all come and go with ./configure flags. The facts here describe the Alpine 3.24.2 package of wolfSSL 5.9.4, built with HAVE_ECC, HAVE_ED25519, HAVE_CURVE25519 and WOLFSSL_HAVE_MLKEM but without HAVE_ED448, HAVE_DILITHIUM, Koblitz or Brainpool curves, or WOLFSSL_ECDSA_DETERMINISTIC_K. A custom build can differ in every one of those.

wc_ecc_sign_hash signs a digest you computed and returns DER; wc_ecc_verify_hash_ex takes r and s as integers for raw signatures. Verification has two outputs: the function's return code says whether it could run, and the int *res argument holds the verdict. A raw 64-byte signature passed to wc_ecc_verify_hash returned -171 (ECC ASN1 bad key data, invalid input) with the verdict 0; code that checks only the return code, or only the verdict, mishandles one of the two cases. The sample prints both.

With this build, nonces are random (deterministic RFC 6979 signing needs WOLFSSL_ECDSA_DETERMINISTIC_K), s is not normalized and high-S signatures verify. Curves covered P-224 to P-521; secp256k1 and Brainpool are absent unless enabled. Ed25519 works, and ML-KEM-768 encapsulated and decapsulated through wc_MlKemKey_*; ML-DSA (Dilithium) is not in this build.

Keys move as DER: wc_EccPublicKeyToDer writes SPKI and wc_EccKeyToDer writes a SEC1 ECPrivateKey; PEM conversion (wc_DerToPem) is available because the package sets WOLFSSL_DER_TO_PEM. The Alpine package declares its license as GPL-3.0-only; commercial licenses are sold separately by wolfSSL Inc. Check encodings against other stacks with the DER ⇄ raw converter.

Facts and the checks behind them

Nothing below is copied from documentation. The check content/libraries/verify/wolfssl/run.sh ran wolfSSL (wolfCrypt) 5.9.4 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

    wc_ecc_sign_hash returns DER; wc_ecc_verify_hash_ex verifies r and s given as integers.

    Recorded by the check
    fact ecdsa-signature-encoding = der
    evidence ecdsa-signature-encoding: wc_ecc_verify_hash_ex with r and s as integers verifies: 1
  • ECDSA nonce

    random

    Random nonce in this build, which lacks WOLFSSL_ECDSA_DETERMINISTIC_K.

    Recorded by the check
    fact ecdsa-nonce = random
    evidence ecdsa-nonce: this build lacks WOLFSSL_ECDSA_DETERMINISTIC_K, so RFC 6979 signing is not available
  • 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

    takes-digest

    wc_ecc_sign_hash and wc_ecc_verify_hash operate on a digest the caller computed.

    Recorded by the check
    fact ecdsa-prehash = takes-digest
    evidence ecdsa-prehash: wc_ecc_sign_hash and wc_ecc_verify_hash take a digest the caller computed
  • Malformed ECDSA signature

    returns-error

    A raw r‖s signature made wc_ecc_verify_hash return -171 (ECC ASN1 bad key data, invalid input) with the verdict 0.

    Recorded by the check
    fact ecdsa-malformed-signature = returns-error
    evidence ecdsa-malformed-signature: wc_ecc_verify_hash on raw r||s: return code -171 (ECC ASN1 bad key data, invalid input), result 0
  • ECDSA curves

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

    P-224, P-256, P-384 and P-521 in this build; secp256k1 and brainpoolP256r1 key generation failed.

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

    Ed25519

    Ed25519; HAVE_ED448 is not set in this build.

    Recorded by the check
    fact eddsa = Ed25519
    evidence eddsa: HAVE_ED448 is not set in this build
  • Post-quantum algorithms

    ML-KEM

    ML-KEM-768 round-tripped through wc_MlKemKey_*; HAVE_DILITHIUM (ML-DSA) is not set in this build.

    Recorded by the check
    fact pqc = ML-KEM
    evidence pqc: HAVE_DILITHIUM (ML-DSA) is not set in this build
  • Public key formats

    spki-der

    wc_EccPublicKeyToDer and wc_EccPublicKeyDecode handle SPKI DER, and the decoded key verified a signature.

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

    sec1-der

    wc_EccKeyToDer writes a SEC1 ECPrivateKey (121 bytes for P-256) that wc_EccPrivateKeyDecode reads back.

    Recorded by the check
    fact private-key-formats = sec1-der
    evidence private-key-formats: wc_EccKeyToDer writes a SEC1 ECPrivateKey of 121 bytes
    evidence private-key-formats: WOLFSSL_DER_TO_PEM is set in this build

Usage

Hash, sign with P-256 and verify, printing both the return code and the verification verdict.
#include <wolfssl/options.h>
#include <wolfssl/wolfcrypt/ecc.h>
#include <wolfssl/wolfcrypt/random.h>
#include <wolfssl/wolfcrypt/sha256.h>
#include <stdio.h>

int main(void) {
    WC_RNG rng;
    ecc_key key;
    unsigned char digest[32], sig[ECC_MAX_SIG_SIZE];
    word32 sig_len = sizeof sig;
    int verified = 0;
    const unsigned char msg[] = "order #1042 approved";

    wc_InitRng(&rng);
    wc_ecc_init(&key);
    wc_ecc_make_key_ex(&rng, 32, &key, ECC_SECP256R1);

    /* wolfCrypt signs a digest you computed and returns DER. */
    wc_Sha256Hash(msg, sizeof msg - 1, digest);
    wc_ecc_sign_hash(digest, sizeof digest, sig, &sig_len, &rng, &key);
    /* The return code says whether verification ran; "verified" holds the verdict. */
    int rc = wc_ecc_verify_hash(sig, sig_len, digest, sizeof digest, &verified, &key);
    printf("rc: %d, verified: %d, DER starts with 0x%02x\n", rc, verified, sig[0]);

    wc_ecc_free(&key);
    wc_FreeRng(&rng);
    return 0;
}

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 build-base wolfssl-dev=5.9.4-r0 >/dev/null
Command
cc -o usage usage.c -lwolfssl && ./usage
Output must match (regular expression)
rc: 0, verified: 1, DER starts with 0x30

Libraries