Skip to content
Draft

FASP #2312

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions activitypub.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function rest_init() {
( new Rest\Application_Controller() )->register_routes();
( new Rest\Collections_Controller() )->register_routes();
( new Rest\Comments_Controller() )->register_routes();
( new Rest\Fasp_Controller() )->register_routes();
( new Rest\Followers_Controller() )->register_routes();
( new Rest\Following_Controller() )->register_routes();
( new Rest\Inbox_Controller() )->register_routes();
Expand All @@ -72,6 +73,8 @@ function plugin_init() {
\add_action( 'init', array( __NAMESPACE__ . '\Comment', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Dispatcher', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Embed', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Fasp', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Wp_Admin\Fasp_Admin', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Handler', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Hashtag', 'init' ) );
\add_action( 'init', array( __NAMESPACE__ . '\Link', 'init' ) );
Expand Down
180 changes: 180 additions & 0 deletions docs/fasp-registration.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
# FASP Registration Implementation

This document describes the WordPress ActivityPub plugin's implementation of the FASP registration specification v0.1.

## Overview

The FASP registration implementation allows external FASP providers to register with this WordPress installation to provide auxiliary services. This follows the [FASP registration specification v0.1](https://github.com/mastodon/fediverse_auxiliary_service_provider_specifications/blob/main/general/v0.1/registration.md).

## Architecture

The implementation uses WordPress options instead of custom database tables for simplicity and compatibility:

- **Registration data**: Stored in `activitypub_fasp_registrations` option
- **Capability data**: Stored in `activitypub_fasp_capabilities` option

## Components

### REST API Endpoints

#### Registration Endpoint (`POST /wp-json/activitypub/1.0/registration`)

Handles registration requests from FASP providers.

**Request format:**
```json
{
"name": "Example FASP",
"baseUrl": "https://fasp.example.com",
"serverId": "b2ks6vm8p23w",
"publicKey": "FbUJDVCftINc9FlgRu2jLagCVvOa7I2Myw8aidvkong="
}
```

**Response format:**
```json
{
"faspId": "dfkl3msw6ps3",
"publicKey": "KvVQVgD4/WcdgbUDWH7EVaYX9W7Jz5fGWt+Wg8h+YvI=",
"registrationCompletionUri": "https://example.com/wp-admin/admin.php?page=activitypub-fasp-registrations&highlight=dfkl3msw6ps3"
}
```

#### Capability Endpoints

- `POST /wp-json/activitypub/1.0/capabilities/{identifier}/{version}/activation` - Enable capability
- `DELETE /wp-json/activitypub/1.0/capabilities/{identifier}/{version}/activation` - Disable capability

### Admin Interface

The admin interface is available at **WP Admin > ActivityPub > FASP Registrations**.

Features:
- View pending registration requests
- Approve or reject registrations
- View approved registrations
- Display public key fingerprints for verification
- Manage registered FASPs

### Classes

#### `Fasp_Controller`
- Handles all FASP REST API endpoints (provider info, registration, capability activation)
- Processes registration requests
- Manages capability activation/deactivation

#### `Fasp`
- Manages registration data using WordPress options
- Provides methods for approval/rejection
- Handles capability management
- Adds FASP base URL to nodeinfo metadata

#### `Fasp_Admin`
- WordPress admin interface (in `wp-admin` folder)
- Registration management UI
- Action handlers for approve/reject/delete

## Security Features

### Ed25519 Keypairs
- Generates Ed25519 keypairs for each registration
- Falls back to secure random strings if sodium extension unavailable
- Stores private keys securely in WordPress options

### Public Key Fingerprints
- SHA-256 fingerprints of public keys for verification
- Displayed in admin interface for manual verification
- Follows FASP specification requirements

### Nonce Protection
- All admin actions protected with WordPress nonces
- CSRF protection for registration management

## Data Storage

### Registration Data Structure
```php
array(
'fasp_id' => 'unique-fasp-id',
'name' => 'FASP Provider Name',
'base_url' => 'https://fasp.example.com',
'server_id' => 'server-id-from-fasp',
'fasp_public_key' => 'base64-encoded-public-key',
'server_public_key' => 'base64-encoded-server-public-key',
'server_private_key' => 'base64-encoded-server-private-key',
'status' => 'pending|approved|rejected',
'requested_at' => 'YYYY-MM-DD HH:MM:SS',
'approved_at' => 'YYYY-MM-DD HH:MM:SS',
'approved_by' => user_id,
)
```

### Capability Data Structure
```php
array(
'fasp_id_capability_vN' => array(
'fasp_id' => 'fasp-id',
'identifier' => 'capability-name',
'version' => 1,
'enabled' => true|false,
'updated_at' => 'YYYY-MM-DD HH:MM:SS',
),
)
```

## Usage Examples

### Testing Registration
```bash
curl -X POST "https://example.com/wp-json/activitypub/1.0/registration" \
-H "Content-Type: application/json" \
-d '{
"name": "Test FASP Provider",
"baseUrl": "https://fasp.example.com",
"serverId": "test-server-123",
"publicKey": "dGVzdC1wdWJsaWMta2V5"
}'
```

### Testing Capability Activation
```bash
# Enable capability
curl -X POST "https://example.com/wp-json/activitypub/1.0/capabilities/trends/1/activation" \
-H "Authorization: Signature ..."

# Disable capability
curl -X DELETE "https://example.com/wp-json/activitypub/1.0/capabilities/trends/1/activation" \
-H "Authorization: Signature ..."
```

## Testing

Run FASP tests (including registration):
```bash
./vendor/bin/phpunit tests/phpunit/tests/includes/class-test-fasp.php
```

## Future Enhancements

1. **Ed25519 Signature Verification**: Implement proper Ed25519 signature verification for capability endpoints
2. **Webhook Notifications**: Notify FASPs when registrations are approved/rejected
3. **Capability Discovery**: Auto-discover supported capabilities from FASP providers
4. **Registration Expiry**: Implement registration expiration and renewal
5. **Audit Logging**: Log all registration and capability changes

## Compliance

This implementation follows the FASP registration specification v0.1:
- ✅ Registration endpoint (`/registration`)
- ✅ Capability activation endpoints (`/capabilities/{id}/{version}/activation`)
- ✅ Ed25519 keypair generation
- ✅ Public key fingerprint verification
- ✅ Admin interface for registration management
- ✅ Registration completion URI
- ⚠️ Ed25519 signature verification (placeholder implementation)

## References

- [FASP Registration Specification v0.1](https://github.com/mastodon/fediverse_auxiliary_service_provider_specifications/blob/main/general/v0.1/registration.md)
- [FASP Protocol Basics](https://github.com/mastodon/fediverse_auxiliary_service_provider_specifications/blob/main/general/v0.1/protocol_basics.md)
- [Ed25519 Signature Specification](https://tools.ietf.org/html/rfc8032)
135 changes: 135 additions & 0 deletions docs/fasp-signatures.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
# FASP Signature Handling Implementation

## Overview

The FASP controller now implements proper HTTP Message Signatures (RFC-9421) for both request authentication and response signing, matching the existing ActivityPub signature infrastructure.

## Request Authentication

### Implementation
```php
public function authenticate_request( $request ) {
// Use the same signature verification as other ActivityPub endpoints
return \Activitypub\Rest\Server::verify_signature( $request );
}
```

### How it Works
1. **Delegates to Server::verify_signature()** - Uses the same authentication as inbox and other ActivityPub endpoints
2. **Signature Verification** - Validates HTTP Message Signatures using either:
- RFC-9421 (HTTP Message Signatures) - Modern standard
- Draft Cavage signatures - Legacy fallback
3. **Key Lookup** - Retrieves public keys from `Remote_Actors` collection using keyid
4. **Content Validation** - Verifies content-digest headers against request body
5. **Timestamp Checks** - Validates created/expires parameters to prevent replay attacks

### Authentication Flow
```
Request → Server::verify_signature() → Signature::verify_http_signature() →
HTTP_Message_Signature::verify() → Public key lookup → Signature validation
```

## Response Signing

### Implementation
```php
private function sign_response( $response, $content ) {
// Create signature components for response
$components = array(
'"@status"' => (string) $response->get_status(),
'"content-digest"' => $response->get_headers()['Content-Digest'] ?? '',
);

// Sign using blog actor's private key
$signature_base = $this->build_signature_base( $components, $params );
\openssl_sign( $signature_base, $signature, $private_key, \OPENSSL_ALGO_SHA256 );

// Add signature headers
$response->header( 'Signature-Input', 'fasp=(' . $identifiers . ')' . $params );
$response->header( 'Signature', 'fasp=:' . $signature_b64 . ':' );
}
```

### How it Works
1. **Uses Blog Actor** - Signs responses with the blog/application actor's private key
2. **RFC-9421 Components** - Signs `@status` and `content-digest` components
3. **Signature Headers** - Adds proper `Signature-Input` and `Signature` headers
4. **Error Handling** - Gracefully fails without breaking responses

## Signature Verification Process

### Incoming Request Verification
1. **Header Parsing** - Extracts `Signature-Input` and `Signature` headers
2. **Component Extraction** - Gets signed components (@method, @target-uri, content-digest)
3. **Key Retrieval** - Looks up public key using keyid parameter
4. **Signature Base** - Rebuilds signature base string per RFC-9421
5. **Cryptographic Verification** - Uses OpenSSL to verify signature
6. **Timestamp Validation** - Checks created/expires parameters

### Response Signing Process
1. **Component Selection** - Signs @status and content-digest for responses
2. **Key Access** - Uses blog actor's private key for signing
3. **Base String Creation** - Follows RFC-9421 signature base format
4. **Signing** - Uses RSA-SHA256 with OpenSSL
5. **Header Addition** - Adds structured signature headers

## Security Features

### Content Integrity
- **Content-Digest**: SHA-256 hash of request/response body
- **Signature Coverage**: Includes digest in signed components
- **Tamper Detection**: Any modification invalidates signature

### Temporal Security
- **Created Parameter**: Timestamp when signature was created
- **Expires Parameter**: Optional expiration time
- **Clock Skew**: Allows reasonable time drift between servers
- **Replay Protection**: Prevents old signatures from being reused

### Key Management
- **KeyId Parameter**: Identifies which key to use for verification
- **Public Key Lookup**: Retrieves keys from remote actor profiles
- **Key Caching**: Remote actors cached for performance
- **Key Rotation**: Supports key updates through actor profile changes

## FASP Specification Compliance

### Required Features ✅
- **Provider Info Endpoint**: Properly authenticated with signatures
- **Content-Digest Headers**: SHA-256 integrity protection
- **HTTP Message Signatures**: RFC-9421 compliance
- **Response Signing**: Signed responses for integrity

### Implementation Details
- **Signature Label**: Uses "fasp" as signature label for responses
- **Algorithm**: RSA-v1.5-SHA256 (same as other ActivityPub endpoints)
- **Components**: @status and content-digest for responses
- **Fallback**: Graceful degradation if signing fails

## Integration with ActivityPub Infrastructure

### Shared Components
- **Signature Class**: Uses existing `Signature::verify_http_signature()`
- **Actor Management**: Leverages `Actors` and `Remote_Actors` collections
- **HTTP Signature Classes**: Uses `Http_Message_Signature` implementation
- **Server Infrastructure**: Integrates with `Rest\Server::verify_signature()`

### Benefits
- **Consistency**: Same signature handling as inbox/outbox
- **Maintenance**: Uses tested and proven signature code
- **Performance**: Shares cached keys and verification logic
- **Standards**: RFC-9421 and draft signature support

## Testing Coverage

### Authentication Tests
- **Signature Verification**: Tests proper delegation to Server::verify_signature()
- **Error Handling**: Validates proper error responses
- **Integration**: Ensures compatibility with existing auth infrastructure

### Response Tests
- **Content-Digest**: Verifies proper digest header generation
- **Signature Headers**: Validates signature header format
- **Error Recovery**: Tests graceful failure when signing fails

This implementation makes the FASP endpoint secure and compliant with both the FASP specification and ActivityPub security standards.
Loading
Loading