gpg_verification.md 5.5 KB

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:

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

curl -H "Authorization: token YOUR_API_TOKEN" \
  https://your-gogs-instance.com/api/v1/user/gpg_keys

Get a Specific GPG Key

curl -H "Authorization: token YOUR_API_TOKEN" \
  https://your-gogs-instance.com/api/v1/user/gpg_keys/1

Delete a GPG Key

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):

    gpg --full-generate-key
    
  2. List your GPG keys:

    gpg --list-secret-keys --keyid-format LONG
    
  3. Export your public key:

    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:

    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:

git commit -m "Your commit message"

Or sign a specific commit:

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