# Universal Cryptographic Signing Protocol for Git
By David Huseby
This document is licensed under the [Creative Commons Attribution 4.0
International (CC BY 4.0) license][0].
This specification documents the new protocol Git uses when interacting with
cryptographic signing and verification tools. The protocol takes is inspired by
the [Assuan Protocol][1] used by GPG to link its component executables
together.
## The Protocol
The protocol is line based with a maximum line length of 1000 octets. All data
is text encoded in UTF-8 encoding. Binary data is encoded as hexadecimal text.
It is designed as a client-server protocol with the client being the initiator
of the connection and the server the receiver. In the case of Git, it uses the
pipe-fork mechanism to spawn a new task and then the protocol is used over the
stdin/stdout pipes between the processes. The pipe-forked child process acts as
the server and the parent Git process is the client.
In the rest of this document, there are example sessions demonstrating the
protocol. In those examples, lines that begin with "S:" are lines sent by the
server (the child process) and lines that begin with "C:" are lines sent by the
client (the git process).
## The Server
The server must support just four commands: OK, ERR, D, and #. Each command is
documented below:
```
OK [<arbitrary debugging information>]
```
The request or operation was successful.
```
ERR errorcode [<human readable error description>]
```
The request or operation failed. The error code is used to signal the exact
error.
```
D <raw data>
```
Sends raw data to the client. There must be exactly one space after the 'D'.
The values for '%', carriage return (0x0d), and line feed (0x0a) must be
escaped using percent escaping of their ascii values in hexadecimal. So '%' is
encoded as '%25' and carriage return and line feed are %0D and %0A
respectively. Only uppercase letters should be used in the hexadecimal
representation. Other characters may be percent escaped for easier debugging.
All data lines are considered one data stream up to a terminating OK or ERR
message.
```
# <string>
```
Comment line issued only for debugging purposes and totally ignored by clients.
In the Assuan protocol documentation there is a command called `INQUIRE` that
is used by servers to ask clients for information required for specific
operations. In this first implementation of the Git signing protocol, the
`INQUIRE` command is specifically excluded because it is not needed for the
immediate goal of supporting commit signing with GPG, GPGSM, and OpenSSH. In
the future, signing tools that have interactive protocols may require the
addition of the `INQUIRE` server command. For now though, it is left out to
simplify implementation.
## The Client
The client must support five basic commands: D, END, OPTION, BYE and #. In
addition they must also support the signing command: SIGN. It also must support
the verification commands: KEY, SIGNATURE, and VERIFY. Each of the commands are
documented below:
```
D <raw data>
```
Sends raw data to the server. This command is the same as the D command
described above in the server section.
```
END
```
Used by the client to mark the end of raw data.
```
OPTION name [[=] value]
```
Sets and option for the current session. Leading and trailing spaces around the
*name* and *value* are allowed but should be ignored. The use of the equal sign
is optional but is suggested if *value* is given.
```
BYE
```
Tells the server the client is finished. The server will respond with OK, then
the client can close the connection.
```
# <string>
```
Comment line issued only for debugging purposes and totally ignored by clients.
```
SIGN
```
The sign command initiates a cryptographic signing operation. Immediately
following the SIGN command, the client must send one or more D commands sending
the server the data to be signed. The data is encoded as hexadecimal string to
simplify client implementation. The data is terminated with an END command,
signaling to the server to sign the data and return the signature.
The server will respond with one or more D commands sending to the client the
resulting data from the SIGN operation. The data sent by the server is
terminated with either an OK command on success or an ERR command on error. The
data sent from the server contains tagged values that are to be stored in the
Git object. These tagged values may include "sigtype", "sigoptions", "sigkey",
and "sig" values. They are significant for the verification process and
described below in the section on verification.
```
KEY <sigkey data>
```
Send "sigkey" data, if any, to the server before a VERIFY command. This is used
for signature schemes that publish the public key along with the signature.
```
SIGNATURE
```
Initiate the transfer of the "sig" data to the server. Immediately following
the SIGNATURE command, the client must send one or more D command sending the
signature data to the server. The data is terminated with an END command. The
server will respond with OK if successful or ERR if there is an error. The
signature data must be sent to the server before a VERIFY command is issued.
```
VERIFY
```
Initiate the transfer of the signed object data to the server and execute the
signature verification operation. Immediately after the VERIFY command, the
client must send one or more D commands to send the signed object data to the
server. The data is terminated with an END command, signaling the server to
execute the signature verification. The server will respond with zero or more
D lines with status information about the digital signature. The server will
then send either an OK, if the verification was successful, or ERR if not.
## Signing a Git Object
The general flow of the Git object signing process is as follows:
1. Git calculates the signing executable to execute from the config file and
command line options.
2. Git pipe-forks a child process to execute the signing executable. For the
purposes of the protocol, Git is the client and the signing tool is the
server.
3. The signing tool starts the session by sending an `OK` command.
4. Git issues zero or more `OPTION` commands to the signing tool to pass the
options from the config file and command line that relate to the signing
operation. The signing tool responds with `OK` in response to each `OPTION`
if the option is valid. If the option is not valid, the signing tool
responds with an `ERR` command and the signing session will en following
steps 8 and 9 below.
5. Git issues the `SIGN` command followed by one or more `D` commands to pass
the Git object data to the signing tool to be signed. Git sends and `END`
command after the last `D` command to signal the end of the data.
6. If the signing tool successfully signs the data, it responds with one or
more `D` commands containing data that must be stored in the Git object
verbatim. The signing tool sends the `OK` command after the last `D` command
to signal a successful signing.
7. If the signing tool fails to sign the data, it responds with zero or more
`D` commands containing detailed error data to be output from Git's stderr
stream. The signing tool sends the `ERR` command after the last `D` command
to signal a failed signing and the optional "reason" string with the `ERR`
command is also output to Git's stderr stream.
8. Git then sends the `BYE` command to conclude the signing session.
9. The signing tool acknowledges the session ending by sending an `OK` command
and exiting execution.
An example successful signing session is illustrated below. The lines beginning
with "S: " are sent from the signing tool to Git and lines starting with "C: "
are sent from Git to the signing tool. **NOTE:** Every byte of the Git object
data passed to the signing tool is significant, this includes the line feed
(0x0A) character at the end of each line. To pass line feed as data to the
signing tool it must be escaped as "%0A". The returned signature data also has
significant line feeds and will also have escaped line feed characters.
```
S: OK
C: OPTION identity=Jane Hacker <jane@h.com>
S: OK
C: OPTION min_trust_level=marginal
S: OK
C: OPTION armored=true
S: OK
C: OPTION detached=true
S: OK
C: SIGN
C: D tag v0.0.1%0A
C: D Tagger: Jane Hacker <jane@h.com>%0A
C: D %0A
C: D First release.%0A
C: END
S: D sigtype:openpgp
S: D sigoption:min_trust_level=marginal
S: D sig:-----BEGIN PGP SIGNATURE-----%0A
S: D sig:%0A
S: D sig:iHUEABYKAB0WIQTXto4BPKlfA2YYS5Pn3hDaTgk8fAUCX5C+ugAKCRDn3hDaTgk8%0A
S: D sig:fOk8AQCRGkdNGMXhJ95e5QIHk44rvfNsyibxY6ZvTXdLQJvt/gEAlFCeEM3SfaDL%0A
S: D sig:8RQR368L0+caDlaZW51VZVP2UBXP6w0=%0A
S: D sig:=1Fby%0A
S: D sig:-----END PGP SIGNATURE-----%0A
S: OK
C: BYE
S: OK
```
An example of a signing session that fails because of a bad `OPTION` set by
Git. In this example Git passes the signing identity and the signing tool does
not have an identity by that name so it responds with the `ERR` command and the
reason for the error.
```
S: OK
C: OPTION identity=Jane Hacker <jane@h.com>
S: ERR Unknown signing identity
C: BYE
S: OK
```
### The Returned Signature Data
When a signing tool generates a successful signature, it sends to Git one or
more `D` commands with signature related data that is intended to be stored
verbatim inside of the Git object. The data is formatted so that Git can easily
execute a signature verification process in the future. Each line of the
signature data starts with a tag and a colon (`:`) followed by data. Each line
is a maximum of 1000 octets including the tag, colon, and the line ending
characters (e.g. newline and/or carriage return).
There are four different tags that may be used in the signature data that are
defined below:
```
sigtype:<signature scheme name>
```
The `sigtype:` tag is used to identify the signing scheme used to generate and
verify this signature. The signature scheme name must match the name used in
the config file and also on the command line. For GPG signatures the scheme
name is `openpgp`. For GPGSM signatures the scheme name is `x509`. For OpenSSH
signatures the scheme name is `openssh`. With this design, Git no longer has to
know any details specific to any signature scheme and nothing needs to be
changed in Git to use new signature schemes in the future. There may only be
one `sigtype:` tagged line in a given signature and it must be the first line
in the signature data.
```
sigoption:<option name> = <option value>
```
The `sigoption:` tag is used by the signing tool to specify options that Git
will pass to the verification tool using the `OPTION` command during a
signature verification session. There may be zero or more `sigoption:` lines in
the signature data.
```
sigkey:<verification key data>
```
The `sigkey:` tag is used by the signing tool to specify the verification key
to be used by the verification tool to verify the signature. There may be zero
or more `sigkey:` lines in the signature data.
```
sig:<signature data>
```
The `sig:` tag is used by the signing tool to specify the signature data it
generated in the signing operation. There may be one or more `sig:` lines in
the signature data and they must come last in the signature.
The resulting signed Git object, in this case a tag, from the successful
signature example above is as follows:
```
tag v0.0.1
Tagger: Jane Hacker <jane@h.com>
First release.
sigtype:openpgp
sigoption:min_trust_level=marginal
sig:-----BEGIN PGP SIGNATURE-----
sig:
sig:iHUEABYKAB0WIQTXto4BPKlfA2YYS5Pn3hDaTgk8fAUCX5C+ugAKCRDn3hDaTgk8
sig:fOk8AQCRGkdNGMXhJ95e5QIHk44rvfNsyibxY6ZvTXdLQJvt/gEAlFCeEM3SfaDL
sig:8RQR368L0+caDlaZW51VZVP2UBXP6w0=
sig:=1Fby
sig:-----END PGP SIGNATURE-----
```
## Verifying a Signed Git Object
The general flow of the signed Git object verification process is as follows:
1. Git parses the `sigtype:` line from the signed object to determine the
signature scheme used to generate the signature.
2. Git calculates the verifying executable to execute from the config file and
command line options using the signature scheme name.
3. Git pipe-forks a child process to execute the verification executable. For
the purposes of the protocol, Git is the client and the verification tool
is the server.
4. The verification tool starts the session by sending an `OK` command.
5. Git parses any `sigoption:` lines from the signed object and issues one
`OPTION` command for each `sigoption:` line. The verification tool sends an
`OK` command in response to each `OPTION` command if the option is valid. If
the option is not valid, the verification tool sends an `ERR` command to
signal failure and the verification session is terminated using steps 10 and
11 below.
6. Git parses any `sigkey:` lines from the signed object and issues the `KEY`
command followed by `D` commands to pass the data from the `sigkey:` lines
to the verification tool. Git sends the `END` command after the last `D`
command to signal the end of the key data. The verification tool then
responds with either an `OK` or `ERR` command to signal success or failure.
On failure the verification session is terminated using steps 10 and 11
below.
7. Git parses the `sig:` lines and issues the `SIGNATURE` command followed by
`D` commands to send the signature data to the verification tool. Git sends
the `END` command after the last `D` command to signal the end of the
signature data. The verification tool responds with either an `OK` or `ERR`
command to signal success or failure. On failure the verification session is
terminated using steps X and Y below.
8. Git sends the `VERIFY` command followed by one or more `D` commands to send
the object data to the verification tool for signature verification. Git
sends the `END` command to signal the end of the object data.
9. The verification tool responds with one or more `D` commands with the
results of the verification process. If the verification process was
successful, the verification tool sends the `OK` command after the last `D`
command to signal the end of the result data. If the verification failed,
the verification tool sends the `ERR` command after the last `D` command to
signal the end of the result data.
10. Git then sends the `BYE` command to end the session.
11. The verification tool acknowledges the session ending by sending an `OK`
command and then exits execution.
An example successful verification session is illustrated below. The lines
beginning with "S: " are sent from the verification tool to Git and lines
starting with "C: " are sent from Git to the signing tool.
```
S: OK
C: OPTION min_trust_level=marginal
S: OK
C: SIGNATURE
C: D -----BEGIN PGP SIGNATURE-----
C: D
C: D iHUEABYKAB0WIQTXto4BPKlfA2YYS5Pn3hDaTgk8fAUCX5C+ugAKCRDn3hDaTgk8
C: D fOk8AQCRGkdNGMXhJ95e5QIHk44rvfNsyibxY6ZvTXdLQJvt/gEAlFCeEM3SfaDL
C: D 8RQR368L0+caDlaZW51VZVP2UBXP6w0=
C: D =1Fby
C: D -----END PGP SIGNATURE-----
C: END
S: OK
C: VERIFY
C: D tag v0.0.1
C: D Tagger: Jane Hacker <jane@h.com>
C: D
C: D First release.
C: END
S: D Sinature made Sun 18 Oct 2020 03:14:17 AM PDT using RSA key ID DFBBCC13
S: D Good signature from "Jane Hacker <jane@h.com>"
S: OK
C: BYE
S: OK
```
An example of a failed verification session is illustrated below.
```
S: OK
C: OPTION min_trust_level=marginal
S: OK
C: SIGNATURE
C: D -----BEGIN PGP SIGNATURE-----
C: D
C: D iHUEABYKAB0WIQTXto4BPKlfA2YYS5Pn3hDaTgk8fAUCX5C+ugAKCRDn3hDaTgk8
C: D 8RQR368L0+caDlaZW51VZVP2UBXP6w0=
C: D =1Fby
C: D -----END PGP SIGNATURE-----
C: END
S: OK
C: VERIFY
C: D tag v0.0.1
C: D Tagger: Jane Hacker <jane@h.com>
C: D
C: D First release.
C: END
S: D Signature made Sun 18 Oct 2020 03:14:17 AM PDT using RSA key ID DFBBCC13
S: D BAD signature from "Jane Hacker <jane@h.com>"
S: ERR
C: BYE
S: OK
```
## Conclusion
The goal of this modification is to make Git able to use any signing and
verification tools that understand this protocol. This eliminates all of the
code that is specific to a signing tool and eases maintenance while increasing
flexibility.
Cheers!
Links
-----
[0]: https://creativecommons.org/licenses/by/4.0/legalcode
[1]: https://www.gnupg.org/documentation/manuals/assuan/index.html