453 lines
11 KiB
Markdown
453 lines
11 KiB
Markdown
# PKI API
|
|
|
|
API Go complète pour gérer une Infrastructure à Clé Publique (PKI) avec hiérarchie de certificats et persistance MongoDB.
|
|
|
|
## Caractéristiques
|
|
|
|
- ✅ **Authentification JWT** : Tous les endpoints protégés par JWT
|
|
- ✅ **Hiérarchie CA** : Support des Root CA, Intermediate CA (Sub-CA) et certificats finaux
|
|
- ✅ **Signature de certificats** : Certificats auto-signés ou signés par une CA
|
|
- ✅ **Gestion des révocations** : Révocation et CRL (Certificate Revocation List)
|
|
- ✅ **Stockage pluggable** : MemoryStore (développement) ou MongoDB (production)
|
|
- ✅ **Export de certificats** : PEM, DER, avec clé privée, chaîne complète
|
|
- ✅ **Clés privées** : Stockage et récupération sécurisés pour tous les certificats (JSON + export fichier)
|
|
- ✅ **Cryptographie** : X.509, RSA 2048-bit, signatures HS256 pour JWT
|
|
|
|
## Architecture
|
|
|
|
```
|
|
pkiapi/
|
|
├── cmd/main.go # Point d'entrée avec config
|
|
├── internal/
|
|
│ ├── api/
|
|
│ │ ├── router.go # Routage Gin
|
|
│ │ ├── auth.go # Login endpoint
|
|
│ │ ├── ca.go # Handlers CAs
|
|
│ │ └── certificates.go # Handlers certificats
|
|
│ ├── auth/
|
|
│ │ ├── jwt.go # JWT manager
|
|
│ │ └── middleware.go # Middleware d'authentification
|
|
│ ├── config/
|
|
│ │ └── config.go # Configuration centralisée
|
|
│ ├── pki/
|
|
│ │ ├── certificate.go # Logique certificats X.509
|
|
│ │ └── errors.go # Erreurs PKI
|
|
│ └── storage/
|
|
│ ├── interface.go # Interface CertificateStore
|
|
│ ├── store.go # MemoryStore (en mémoire)
|
|
│ ├── mongo.go # MongoStore (persistance)
|
|
│ ├── util.go # Helpers sérialisation
|
|
│ └── errors.go # Erreurs storage
|
|
├── tests/ # Scripts de test
|
|
├── go.mod
|
|
└── docker-compose.yaml # Orchestration services
|
|
```
|
|
|
|
## Démarrage rapide
|
|
|
|
### 1. Installer et compiler
|
|
|
|
```bash
|
|
go mod download
|
|
go build -o pkiapi ./cmd/main.go
|
|
```
|
|
|
|
### 2. Démarrer le serveur
|
|
|
|
**Mode développement (MemoryStore):**
|
|
```bash
|
|
export STORAGE_TYPE=memory
|
|
export PORT=8080
|
|
./pkiapi
|
|
# Serveur lancé sur http://localhost:8080
|
|
```
|
|
|
|
**Mode production (MongoDB via Docker Compose):**
|
|
```bash
|
|
docker compose up -d --build
|
|
# L'API est disponible sur http://localhost:8080
|
|
# MongoDB est disponible sur mongodb://localhost:27017
|
|
```
|
|
|
|
### 3. Obtenir un token JWT
|
|
|
|
```bash
|
|
curl -X POST http://localhost:8080/api/v1/login \
|
|
-H "Content-Type: application/json" \
|
|
-d '{"username":"admin","password":"admin"}'
|
|
|
|
# Réponse:
|
|
# {
|
|
# "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
# "expires_in": 86400
|
|
# }
|
|
```
|
|
|
|
## API Endpoints
|
|
|
|
### 🔐 Authentification (Public)
|
|
|
|
#### POST /api/v1/login
|
|
Obtient un token JWT pour accéder aux autres endpoints.
|
|
|
|
**Requête :**
|
|
```bash
|
|
curl -X POST http://localhost:8080/api/v1/login \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"username": "admin",
|
|
"password": "admin"
|
|
}'
|
|
```
|
|
|
|
**Réponse :**
|
|
```json
|
|
{
|
|
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
|
"expires_in": 86400
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
### 🔑 Autorités de Certification (Authentifiés)
|
|
|
|
#### POST /api/v1/ca
|
|
Crée une nouvelle autorité de certification auto-signée.
|
|
|
|
**Requête :**
|
|
```bash
|
|
TOKEN="<your_token>"
|
|
curl -X POST http://localhost:8080/api/v1/ca \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"subject": "CN=Root CA,O=Example Inc,C=FR",
|
|
"validity_days": 3650
|
|
}'
|
|
```
|
|
|
|
**Réponse :**
|
|
```json
|
|
{
|
|
"ca": {
|
|
"id": "ff3ac5c5-08d1-401b-9e83-f18eda4c538b",
|
|
"subject": "CN=Root CA,O=Example Inc,C=FR",
|
|
"not_before": "2025-12-06T21:45:01Z",
|
|
"not_after": "2035-12-04T21:45:01Z",
|
|
"serial_number": "546965196",
|
|
"certificate": "MIIC5zCCAc+gAwIBAgIDCkUz...",
|
|
"private_key": "MIIEwAIBADANBgkqhkiG9w0BAQE...",
|
|
"is_ca": true
|
|
},
|
|
"created_by": "admin"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### GET /api/v1/ca/:id
|
|
Récupère une autorité de certification par ID (avec clé privée).
|
|
|
|
**Requête :**
|
|
```bash
|
|
TOKEN="<your_token>"
|
|
CA_ID="ff3ac5c5-08d1-401b-9e83-f18eda4c538b"
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
http://localhost:8080/api/v1/ca/$CA_ID
|
|
```
|
|
|
|
**Réponse :**
|
|
```json
|
|
{
|
|
"ca": {
|
|
"id": "ff3ac5c5-08d1-401b-9e83-f18eda4c538b",
|
|
"subject": "CN=Root CA,O=Example Inc,C=FR",
|
|
"not_before": "2025-12-06T21:45:01Z",
|
|
"not_after": "2035-12-04T21:45:01Z",
|
|
"serial_number": "546965196",
|
|
"certificate": "MIIC5zCCAc+gAwIBAgIDCkUz...",
|
|
"private_key": "MIIEwAIBADANBgkqhkiG9w0BAQE...",
|
|
"is_ca": true
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### POST /api/v1/ca/sign
|
|
Crée une CA intermédiaire (Sub-CA) signée par une CA parent.
|
|
|
|
**Requête :**
|
|
```bash
|
|
TOKEN="<your_token>"
|
|
PARENT_CA_ID="ff3ac5c5-08d1-401b-9e83-f18eda4c538b"
|
|
curl -X POST http://localhost:8080/api/v1/ca/sign \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"parent_ca_id\": \"$PARENT_CA_ID\",
|
|
\"subject\": \"CN=Intermediate CA,O=Example Inc,C=FR\",
|
|
\"validity_days\": 1825
|
|
}"
|
|
```
|
|
|
|
---
|
|
|
|
### 📜 Certificats (Authentifiés)
|
|
|
|
#### POST /api/v1/certificates
|
|
Crée un certificat auto-signé avec clé privée.
|
|
|
|
**Requête :**
|
|
```bash
|
|
TOKEN="<your_token>"
|
|
curl -X POST http://localhost:8080/api/v1/certificates \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d '{
|
|
"subject": "CN=example.com,O=Example Inc,C=FR",
|
|
"validity_days": 365
|
|
}'
|
|
```
|
|
|
|
**Réponse :**
|
|
```json
|
|
{
|
|
"certificate": {
|
|
"id": "8e77050f-d19f-4607-8c49-b974c5f9cb08",
|
|
"subject": "CN=example.com,O=Example Inc,C=FR",
|
|
"issuer": "CN=example.com,O=Example Inc,C=FR",
|
|
"not_before": "2025-12-06T21:41:38Z",
|
|
"not_after": "2026-12-06T21:41:38Z",
|
|
"serial_number": "673075",
|
|
"certificate": "MIIC5zCCAc+gAwIBAgIDCkUzMA0GCSq...",
|
|
"private_key": "MIIEwAIBADANBgkqhkiG9w0BAQE...",
|
|
"revoked": false
|
|
},
|
|
"created_by": "admin"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### GET /api/v1/certificates/:id
|
|
Récupère un certificat par ID (avec clé privée encodée en base64).
|
|
|
|
**Requête :**
|
|
```bash
|
|
TOKEN="<your_token>"
|
|
CERT_ID="e12e08a9-adeb-404c-a7b7-a613b77dfe66"
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
http://localhost:8080/api/v1/certificates/$CERT_ID
|
|
```
|
|
|
|
**Réponse :**
|
|
```json
|
|
{
|
|
"certificate": {
|
|
"id": "e12e08a9-adeb-404c-a7b7-a613b77dfe66",
|
|
"subject": "CN=server.example.com,O=Example Inc,C=FR",
|
|
"issuer": "CN=Intermediate CA,O=Example Inc,C=FR",
|
|
"not_before": "2025-12-06T21:45:09Z",
|
|
"not_after": "2026-12-06T21:45:09Z",
|
|
"serial_number": "46798982",
|
|
"certificate": "MIIDFDCCAfygAwIBAgIEAsoYhjANBg...",
|
|
"private_key": "MIIEwAIBADANBgkqhkiG9w0BAQE...",
|
|
"revoked": false
|
|
}
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
#### POST /api/v1/certificates/sign
|
|
Signe un certificat avec une CA (avec clé privée).
|
|
|
|
**Requête :**
|
|
```bash
|
|
TOKEN="<your_token>"
|
|
CA_ID="b2350d39-53c2-469a-802c-acc39707e352"
|
|
curl -X POST http://localhost:8080/api/v1/certificates/sign \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"ca_id\": \"$CA_ID\",
|
|
\"subject\": \"CN=server.example.com,O=Example Inc,C=FR\",
|
|
\"validity_days\": 365
|
|
}"
|
|
```
|
|
|
|
---
|
|
|
|
#### POST /api/v1/revoke
|
|
Révoque un certificat.
|
|
|
|
**Requête :**
|
|
```bash
|
|
TOKEN="<your_token>"
|
|
CERT_ID="e12e08a9-adeb-404c-a7b7-a613b77dfe66"
|
|
curl -X POST http://localhost:8080/api/v1/revoke \
|
|
-H "Authorization: Bearer $TOKEN" \
|
|
-H "Content-Type: application/json" \
|
|
-d "{
|
|
\"certificate_id\": \"$CERT_ID\",
|
|
\"reason\": \"Compromised key\"
|
|
}"
|
|
```
|
|
|
|
---
|
|
|
|
#### GET /api/v1/crl
|
|
Récupère la Certificate Revocation List (liste des certificats révoqués).
|
|
|
|
**Requête :**
|
|
```bash
|
|
TOKEN="<your_token>"
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
http://localhost:8080/api/v1/crl
|
|
```
|
|
|
|
---
|
|
|
|
### 📥 Export de Certificats (Authentifiés)
|
|
|
|
#### GET /api/v1/certificates/:id/export/pem
|
|
Exporte un certificat au format PEM.
|
|
|
|
```bash
|
|
TOKEN="<your_token>"
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
http://localhost:8080/api/v1/certificates/:id/export/pem \
|
|
-o certificate.pem
|
|
```
|
|
|
|
#### GET /api/v1/certificates/:id/export/der
|
|
Exporte un certificat au format DER (binaire).
|
|
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
http://localhost:8080/api/v1/certificates/:id/export/der \
|
|
-o certificate.der
|
|
```
|
|
|
|
#### GET /api/v1/certificates/:id/export/pem-with-key
|
|
Exporte certificat + clé privée au format PEM.
|
|
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
http://localhost:8080/api/v1/certificates/:id/export/pem-with-key \
|
|
-o certificate_with_key.pem
|
|
```
|
|
|
|
#### GET /api/v1/certificates/:id/export/chain
|
|
Exporte la chaîne complète (certificat + CA parent).
|
|
|
|
```bash
|
|
curl -H "Authorization: Bearer $TOKEN" \
|
|
http://localhost:8080/api/v1/certificates/:id/export/chain \
|
|
-o certificate_chain.pem
|
|
```
|
|
|
|
---
|
|
|
|
## Clés Privées
|
|
|
|
### Stockage et Récupération
|
|
|
|
Les clés privées sont **automatiquement stockées** pour:
|
|
- ✅ Tous les certificats auto-signés
|
|
- ✅ Tous les certificats signés par une CA
|
|
- ✅ Toutes les CAs (Root et Intermediate)
|
|
|
|
### Accès via JSON
|
|
|
|
Les clés privées sont incluses dans les réponses JSON:
|
|
- **Format**: Base64 PKCS#8 encodé
|
|
- **Champs**: `private_key` (optionnel, présent si disponible)
|
|
- **Endpoints retournant des clés privées**:
|
|
- `POST /api/v1/ca` - Création CA
|
|
- `GET /api/v1/ca/:id` - Récupération CA
|
|
- `POST /api/v1/ca/sign` - Création Sub-CA
|
|
- `POST /api/v1/certificates` - Création certificat
|
|
- `GET /api/v1/certificates/:id` - Récupération certificat
|
|
- `POST /api/v1/certificates/sign` - Signature certificat
|
|
|
|
### Accès via Export Fichier
|
|
|
|
Les clés privées peuvent aussi être exportées en fichier:
|
|
- **`/export/pem-with-key`** - Certificat + clé privée en PEM
|
|
- **`/export/chain`** - Chaîne complète (pour CAs parent)
|
|
|
|
### Base de Données
|
|
|
|
Les clés privées sont:
|
|
- ✅ Sauvegardées en MongoDB (champ `private_key` en base64)
|
|
- ✅ Chiffrées au repos (via votre configuration MongoDB)
|
|
- ✅ Accessibles uniquement avec authentification JWT
|
|
|
|
---
|
|
|
|
## Tests
|
|
|
|
### Scripts de Test Disponibles
|
|
|
|
```bash
|
|
# Test complet (création CA, certificats, exports, revocation)
|
|
./tests/test_complete.sh
|
|
|
|
# Test spécifique des exports
|
|
./tests/test_exports.sh
|
|
|
|
# Test du stockage des clés privées
|
|
./tests/test_private_keys.sh
|
|
```
|
|
|
|
### Résultats des Tests
|
|
|
|
Voir `tests/test_results.txt` pour les résultats détaillés des tests.
|
|
|
|
---
|
|
|
|
## Variables d'Environnement
|
|
|
|
```bash
|
|
# Stockage
|
|
export STORAGE_TYPE=memory # memory ou mongodb (défaut: memory)
|
|
export MONGO_URI=mongodb://localhost:27017
|
|
export MONGO_DB=pkiapi
|
|
|
|
# Serveur
|
|
export PORT=8080
|
|
export JWT_SECRET_KEY=your-secret-key
|
|
export GIN_MODE=release
|
|
```
|
|
|
|
---
|
|
|
|
## Conventions de Code
|
|
|
|
- **Gestion des erreurs** : Propagation simple sans wrapper
|
|
- **Concurrence** : `sync.RWMutex` pour le store
|
|
- **Cryptographie** : Stdlib Go (crypto/x509, crypto/rsa, crypto/rand)
|
|
- **JWT** : github.com/golang-jwt/jwt/v5
|
|
- **MongoDB** : go.mongodb.org/mongo-driver
|
|
|
|
---
|
|
|
|
## Améliorations Futures
|
|
|
|
- [x] Export des certificats (PEM, DER)
|
|
- [x] Clés privées dans JSON responses
|
|
- [ ] Support OCSP (Online Certificate Status Protocol)
|
|
- [ ] Interface web pour gérer les CAs
|
|
- [ ] Auditing et logging complet
|
|
- [ ] Rate limiting et throttling
|
|
- [ ] Support HSM (Hardware Security Module)
|
|
|
|
---
|
|
|
|
## Licence
|
|
|
|
MIT
|