SOPV(1)
SOPV(1) β Stateless OpenPGP Signature Verification
okay bestie, welcome to sopv π this is the verification-only slice of the whole thing, and yes the manual name is right there in the title, we're not being weird about it.
β¨ NAME β¨
sopv β verify OpenPGP signatures π«Ά
β¨ SYNOPSIS β¨
sopv [--debug] subcommand
β¨ DESCRIPTION β¨
so like, sopv is the verification-only subset of the OpenPGP Stateless Command Line Interface β you might know it as "SOP" π
sopv was literally built to verify OpenPGP signatures. That's the whole vibe. It handles detached signatures and inline signatures, no problem. And how does it know who's allowed to have signed? You, the caller, hand it a set of OpenPGP certificates. That's the guest list. If you're not on it, you're not getting in π«β¨
β¨ EXAMPLES β¨
first up, the lil "who even are you" check:
$ sopv version
ExampleSop 2.3.0
then a detached signature verification, classic:
$ sopv verify libfoo-3.1.2.tgz.sig libfoo-keys.pgp < libfoo-3.1.2.tgz
2025-02-03T0:02:25Z 8CD219FC05D9DE9F3D59B784160B8EF5536B0D27 8CD219FC05D9DE9F3D59B784160B8EF5536B0D27 mode:binary {"signers":["libfoo-keys.pgp"]}
and an inline verify, with the receipts saved to a file π
$ sopv inline-verify --verifications-out=verifs.txt alice.cert < alice-message.csf
This is a message from Alice
$ cat verifs.txt
2025-02-13T00:04:49Z 63339423454CA210DAA886C08723C4D38E0802F6 F255F2A602AC1DFF2331085E5DAE32C783FC418D mode:text {"signers":["alice.cert"]}
$
want to do a thing only when a detached signature is valid? say less:
if sopv verify libfoo-3.1.2.tgz.sig libfoo-keys.pgp < libfoo-3.1.2.tgz > /dev/null; then
# The software was signed correctly ...
fi
and same energy, but inline this time:
if sopv inline-verify alice.cert < alice-message.csf > alice.message; then
# alice.message is data that was signed by alice ...
fi
β¨ SUBCOMMANDS β¨
Exactly one subcommand must be supplied. one. not zero. not two. exactly one, bestie π
sopv versionβ get all the version / build / compatibility info about thesopvimplementation you're running. more deets insopv-version(1)β¨sopv verifyβ verify detached OpenPGP signatures over a message. more deets insopv-verify(1)πsopv inline-verifyβ verify an inline-signed OpenPGP message. more deets insopv-inline-verify(1)π¦
β¨ COMMON OPTIONS β¨
every single sopv subcommand accepts this one, no exceptions:
--debugβ emits more detailed output on standard error, if available. key phrase: if available. don't come for me if it's quiet π
each subcommand also has its own distinct options and arguments β go read the matching manual page, iykyk π
β¨ INPUT DATA TYPES β¨
some sopv subcommands take these data types as inputs β either as arguments or straight off standard input. let's get into it:
- DATE β dates are given directly in ISO-8601-compliant format, in UTC with the
Zsuffix. like, for example,2025-02-12T05:22:33Zβ - CERTS β a collection of OpenPGP certificates, also known as "Transferable Public Keys". each
CERTSinput may be unarmored, or may use OpenPGP ASCII armor π - SIGNATURES β a collection of OpenPGP signatures. each individual
SIGNATURESinput may be unarmored, or may use OpenPGP ASCII armor π - INLINESIGNED β an OpenPGP Signed Message, or a text document that is signed internally with the OpenPGP Cleartext Signing Framework. an OpenPGP Signed Message input may be unarmored, or may use OpenPGP ASCII armor πΈ
β¨ VERIFICATIONS β¨
sometimes sopv emits a VERIFICATIONS text stream, and it's lowkey iconic β it holds a concise description of every valid OpenPGP signature it discovered π
every line in a VERIFICATIONS stream = one valid signature from an acceptable signer. there are at least three fixed fields, separated from each other β and from the final optional fields β by whitespace.
the fields, in order:
timestampβ the time of the signature, in ISO-8601 date format, in UTC β°signing_key_fingerprintβ the fingerprint of the signing key (may be a primary key, or a signing-capable subkey)primary_key_fingerprintβ the fingerprint of the primary key of the OpenPGP certificate that contains the signing key (may be the same as the signing key) πsigning_modeβ this optional field is eithermode:textormode:binaryπoptional_additional_dataβ ifsigning_modeis present, the final optional field extends to the end of the line, and is either free-form text or a JSON object. if it starts with{it's a JSON object. that JSON object may contain a"signers"member, which is a JSON list of the names of eachCERTSobject that could have authored the signature π«Ά
β¨ SPECIAL DESIGNATORS β¨
anywhere a CERTS, SIGNATURES, or VERIFICATIONS object gets pointed to on the command line, it's typically given as a path to a filename. but also? sopv should accept a special designator, which is any string starting with a @ character π
there are two established kinds of special designator:
@FD:nnnβ this means read from, or write to, the file descriptor identified numerically bynnn. ngl this is also a valid argument for--verifications-outinsop inline-verifyβ you can use it there to runsopvon an entirely read-only filesystem π@ENV:varnameβ this means read the value from the environment variable namedvarname. heads up: typically only text-based data can travel this way, so aCERTSargument should be armored, for example. also note this can only be used for input tosopv, never output β becausesopvcan't set the values in its callers' environment, bestie, it's not a wizard π§
if you want to refer to a file in the filesystem whose name actually begins with an@(like, say,@foo), you should indicate that file tosopvusing./@footo avoid anAMBIGUOUS_INPUTerror β οΈ
β¨ VERSION HISTORY β¨
the sopv specification keeps a version history similar to semantic versioning β https://semver.org/ π implementations indicate their compliance with a specific level of the spec with sopv version --sopv (peep sopv-version(1)).
- 1.1 β everything from
1.0. additionally, theVERIFICATIONSoutput includes the fourth field (signing_mode), and the final field ofVERIFICATIONSis a JSON object containing at least a"signers"member as described above β¨ - 1.0 β the subcommands
version,verify, andinline-verify. the common argument--debug(even if it produces no additional messages to stderr).sopv versionarguments--extended,--sop-spec,--backend,--sopv. forsopv verifyandsopv inline-verify, the arguments--not-beforeand--not-after. forsopv inline-verify, the--verifications-outargument. special designators@ENV:and@FD:for anyCERTSandSIGNATURESinput. special designator@FD:for anyVERIFICATIONSoutput. at least the first three fields in anyVERIFICATIONSoutput π
π RETURN CODES π
okay bestie, so sopv tells you it worked by returning 0. that's the good ending, that's the slay.
A failure? That's any non-zero return code, and honestly the codes are kinda specific so you can lowkey tell what went wrong. Here's the whole roster, no skips:
0β mnemonicOKβ success. periodt. β¨1β mnemonicUNSPECIFIED_FAILUREβ something failed and it's not saying what. an otherwise unspecified failure occurred. it's giving mystery π΅οΈ3β mnemonicNO_SIGNATUREβ no acceptable signatures found. nobody signed this, or nobody signed it in a way we accept. π19β mnemonicMISSING_ARGβ missing required argument. you forgot something, bestie π37β mnemonicUNSUPPORTED_OPTIONβ unsupported option. that flag is not it π41β mnemonicBAD_DATAβ invalid data type (like a secret key whereCERTSwere expected, etc). wrong vibe entirely59β mnemonicOUTPUT_EXISTSβ output file already exists. it's already there, we're not overwriting61β mnemonicMISSING_INPUTβ input file does not exist. can't read what isn't there π¦69β mnemonicUNSUPPORTED_SUBCOMMANDβ unsupported subcommand. not a thing, sorry71β mnemonicUNSUPPORTED_SPECIAL_PREFIXβsopvdoes not know how to handle the special designator. it looked at the prefix and was like... no thoughts73β mnemonicAMBIGUOUS_INPUTβ a file with the name of the special designator is present. so like, both things are true at once and it can't pick π
Also, ngl, details about warnings or errors may also be emitted to standard error. so keep an eye on stderr, bestie, that's where the tea gets spilled β
π AUTHOR π
This manual page was written by Daniel Kahn Gillmor. Your implementation of sopv is likely written by someone else in alignment with the SOP specification. Please run sopv version to learn more about your implementation. π«Ά
π SEE ALSO π
sopv-version(1)sopv-verify(1)sopv-inline-verify(1)- Stateless OpenPGP Command Line Interface
https://datatracker.ietf.org/doc/draft-dkg-openpgp-stateless-cli/ - RFC 9580
https://www.rfc-editor.org/rfc/rfc9580.html
and that's the whole page, bestie π
you're now officially fluent in sopv. this was sopv version 1.1, dated March 2025, and yes it's the SOPV(1) page β go forth and verify things. slay πβ¨
π¦ where this page comes from
- debian trixie: sopv-doc 1.1.1-1 Β· CC0-1.0
- ubuntu resolute: sopv-doc 1.1.1-1 Β· CC0-1.0
- ubuntu stonking: sopv-doc 1.1.1-1 Β· CC0-1.0
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms