A .NET implementation of JSON Signature Scheme (JSS) as defined in ITU-T X.590 (10/2023) — a method for digitally signing JSON objects while keeping them in JSON format.
JSS embeds cryptographic signatures directly within JSON objects, using JSON Canonicalization Scheme (JCS/RFC 8785) for deterministic serialization and a two-step hash-then-sign process. Unlike JWS/JWT where signatures are separate from the data, JSS keeps signature and payload together in a single JSON structure.
- Single signatures, multiple independent signatures, and countersignatures (nested signatures on existing signatures)
- 12 algorithms: ECDSA (ES256/384/512), RSA PKCS#1 v1.5 (RS256/384/512), RSA-PSS (PS256/384/512), EdDSA (Ed25519/Ed448)
- Embedded public keys (PEM SubjectPublicKeyInfo format)
- X.509 certificate chain support
- Non-mutating — all operations return new documents
- Accepts both
JsonObjectandstringinputs
- .NET 8.0+
| Project | Description | Details |
|---|---|---|
| CoderPatros.Jss | .NET library for signing and verifying JSON documents | Library README |
| CoderPatros.Jss.Cli | Command-line tool for key generation, signing, and verification | CLI README |
| CoderPatros.Jss.Api | REST API for key generation, signing, and verification | API README |
| CoderPatros.Jss.Web | Browser-based tool for key generation, signing, and verification | Web README |
using CoderPatros.Jss;
using CoderPatros.Jss.Keys;
using CoderPatros.Jss.Models;
using System.Text.Json.Nodes;
// Generate a key pair
var (signingKey, verificationKey, publicKeyPemBody) = PemKeyHelper.GenerateKeyPair("ES256");
// Sign a document
var service = new JssSignatureService();
var doc = new JsonObject { ["message"] = "Hello, world!" };
var signed = service.Sign(doc, new SignatureOptions
{
Algorithm = "ES256",
HashAlgorithm = "sha-256",
Key = signingKey,
PublicKey = publicKeyPemBody
});
// Verify
var result = service.Verify(signed, new VerificationOptions
{
AllowEmbeddedPublicKey = true
});
Console.WriteLine(result.IsValid); // True
signingKey.Dispose();
verificationKey.Dispose();See the Library README for the full API reference, countersignatures, key management, and more.
Build from source:
dotnet build src/CoderPatros.Jss.CliGenerate keys, sign, and verify:
# Generate an ECDSA key pair
jss-cli generate-key -a ES256
# Sign a document
jss-cli sign -a ES256 -h sha-256 -k ES256-private.pem -i document.json > signed.json
# Verify the signature
jss-cli verify -k ES256-public.pem -i signed.json
# Output: ValidThe CLI also supports stdin/stdout piping, countersigning, embedded public keys, and algorithm whitelisting. See the CLI README for the full command reference.
Run the API server from source:
dotnet run --project src/CoderPatros.Jss.ApiOr with Docker:
./src/CoderPatros.Jss.Api/docker-run.shGenerate keys, sign, and verify with curl:
# Generate an ECDSA key pair
curl -s -X POST http://localhost:5000/api/keys/generate \
-H "Content-Type: application/json" \
-d '{"algorithm":"ES256"}'
# Sign a document (use privateKeyPem and algorithm from the generate response)
curl -s -X POST http://localhost:5000/api/sign \
-H "Content-Type: application/json" \
-d '{"document":{"message":"hello"},"algorithm":"ES256","hashAlgorithm":"sha-256","privateKeyPem":"..."}'
# Verify the signature
curl -s -X POST http://localhost:5000/api/verify \
-H "Content-Type: application/json" \
-d '{"document":{...},"allowEmbeddedKey":true}'
# Output: {"isValid":true,"error":null}The API also supports countersigning and verifying all signatures. See the API README for the full endpoint reference.
Run the web tool locally:
dotnet run --project src/CoderPatros.Jss.WebOr with Docker:
./src/CoderPatros.Jss.Web/docker-run.shOpen the app in your browser to generate keys, sign documents, and verify signatures. All cryptographic operations run entirely in the browser — your keys and documents never leave your machine. See the Web README for more details.
- A copy of the document is made and any existing
signaturesarray is removed - A signature object is created with
algorithm,hash_algorithm, and optionallypublic_key— but novalueyet - The signature object is placed as the sole entry in a
signaturesarray on the document - The entire document is canonicalized using JCS (RFC 8785)
- The canonical bytes are hashed using the specified
hash_algorithm - The hash is signed with the private key and the base64url-encoded result is set as
value - The original signatures are restored at the start of the array, with the new signature appended at the end
Verification reverses the process: remove value, rebuild the document with just that signature, canonicalize, hash, and verify.
dotnet testApache-2.0