# GPG Commit Signature Verification This feature allows users to sign their Git commits with GPG keys and verify the authenticity of commits. ## Features ### 1. GPG Key Management Users can manage their GPG public keys through the API: - **List GPG Keys**: `GET /api/v1/user/gpg_keys` - **Get GPG Key**: `GET /api/v1/user/gpg_keys/:id` - **Add GPG Key**: `POST /api/v1/user/gpg_keys` - **Delete GPG Key**: `DELETE /api/v1/user/gpg_keys/:id` #### Adding a GPG Key To add a GPG key via API: ```bash curl -X POST \ -H "Authorization: token YOUR_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"armored_public_key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...\n-----END PGP PUBLIC KEY BLOCK-----"}' \ https://your-gogs-instance.com/api/v1/user/gpg_keys ``` ### 2. Commit Signature Verification Commits signed with GPG can be verified against the user's imported GPG keys. #### How It Works 1. User imports their GPG public key through the API 2. User signs commits locally with `git commit -S` 3. When commits are pushed, Gogs can verify the signatures 4. Verification status is stored and can be displayed in the UI #### Verification Process The verification process: 1. Extracts the GPG signature from the Git commit object 2. Finds the commit author's user account by email 3. Retrieves all valid (non-expired) signing keys for the user 4. Attempts to verify the signature against the keyring 5. Returns verification status (verified, unverified, or invalid) ### 3. Database Schema The `gpg_key` table stores user GPG keys: - `id`: Primary key - `owner_id`: User ID who owns the key - `key_id`: Short GPG key ID (16 characters) - `fingerprint`: Full 40-character fingerprint - `content`: ASCII-armored public key - `can_sign`: Whether the key can sign commits - `can_encrypt`: Whether the key can encrypt data - `emails`: JSON array of email addresses in the key - `created_unix`: Creation timestamp - `updated_unix`: Last update timestamp - `expired_unix`: Expiration timestamp (0 if never expires) ## Implementation Details ### Backend Components 1. **Database Layer** (`internal/database/gpg_keys.go`): - `GPGKey` model - `GPGKeysStore` with CRUD operations 2. **GPG Utilities** (`internal/gpgutil/gpg.go`): - `ParsePublicKey()`: Parse and extract key information - `VerifyCommitSignature()`: Verify commit signatures - `ExtractSignature()`: Extract signature from Git commit object - `CreateKeyring()`: Create OpenPGP keyring from keys 3. **API Endpoints** (`internal/route/api/v1/user/gpg_key.go`): - GPG key CRUD operations - Input validation and error handling 4. **Verification Service** (`internal/database/gpg_verification.go`): - `VerifyCommitSignature()`: High-level verification method ### Migration The database migration (`v23`) creates the `gpg_key` table automatically on startup. ## Security Considerations 1. **Key Storage**: Only public keys are stored; private keys remain on user machines 2. **Signature Verification**: Uses the standard OpenPGP library for cryptographic verification 3. **Key Expiration**: Expired keys are excluded from verification 4. **Email Matching**: Commit author email must match an email in the GPG key ## Future Enhancements The following features are planned but not yet implemented: 1. **UI Components**: - User settings page for GPG key management - Verification badges on commit views - Visual indicators in commit history 2. **Additional Features**: - Required signed commits per repository - Webhook notifications for unsigned commits - SSH key signatures support - Key revocation checking ## API Examples ### List Your GPG Keys ```bash curl -H "Authorization: token YOUR_API_TOKEN" \ https://your-gogs-instance.com/api/v1/user/gpg_keys ``` ### Get a Specific GPG Key ```bash curl -H "Authorization: token YOUR_API_TOKEN" \ https://your-gogs-instance.com/api/v1/user/gpg_keys/1 ``` ### Delete a GPG Key ```bash curl -X DELETE \ -H "Authorization: token YOUR_API_TOKEN" \ https://your-gogs-instance.com/api/v1/user/gpg_keys/1 ``` ## Signing Commits with GPG ### Setup 1. Generate a GPG key (if you don't have one): ```bash gpg --full-generate-key ``` 2. List your GPG keys: ```bash gpg --list-secret-keys --keyid-format LONG ``` 3. Export your public key: ```bash gpg --armor --export YOUR_KEY_ID ``` 4. Add the exported public key to Gogs via the API 5. Configure Git to use your GPG key: ```bash git config --global user.signingkey YOUR_KEY_ID git config --global commit.gpgsign true ``` ### Signing Commits With `commit.gpgsign` enabled, all commits will be signed automatically: ```bash git commit -m "Your commit message" ``` Or sign a specific commit: ```bash git commit -S -m "Signed commit message" ``` ## Troubleshooting ### Key Not Found If verification fails with "no GPG keys found", ensure: - The commit author email matches your Gogs user email - You've imported your public key via the API - The key hasn't expired ### Signature Verification Failed If verification fails with "signature verification failed": - Ensure the commit was signed with the correct private key - Check that the public key in Gogs matches your private key - Verify the key hasn't been revoked or expired ## References - [Git Commit Signing](https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work) - [GPG/PGP Basics](https://www.gnupg.org/gph/en/manual.html) - [GitHub GPG Documentation](https://docs.github.com/en/authentication/managing-commit-signature-verification)