first commit
This commit is contained in:
386
API.md
Normal file
386
API.md
Normal file
@@ -0,0 +1,386 @@
|
||||
# Dummy CA - API Dokumentation
|
||||
|
||||
Diese Dokumentation beschreibt die REST-API für die externe Anbindung an die Dummy CA.
|
||||
|
||||
**Base URL:** `http://localhost:8088` (oder die entsprechende Server-Adresse)
|
||||
|
||||
---
|
||||
|
||||
## Endpunkte
|
||||
|
||||
### 1. Health Check
|
||||
|
||||
Prüft, ob der Server erreichbar ist.
|
||||
|
||||
**Endpoint:** `GET /health`
|
||||
|
||||
**Response:**
|
||||
```json
|
||||
{
|
||||
"status": "ok"
|
||||
}
|
||||
```
|
||||
|
||||
**Status Codes:**
|
||||
- `200 OK` - Server ist erreichbar
|
||||
|
||||
---
|
||||
|
||||
### 2. CSR einreichen und signieren
|
||||
|
||||
Reicht einen Certificate Signing Request (CSR) ein und lässt ihn signieren.
|
||||
|
||||
**Endpoint:** `POST /csr`
|
||||
|
||||
**Content-Type:** `application/json`
|
||||
|
||||
**Request Body:**
|
||||
```json
|
||||
{
|
||||
"csr": "BASE64_ENCODED_CSR_PEM",
|
||||
"action": "sign",
|
||||
"validity_days": 365
|
||||
}
|
||||
```
|
||||
|
||||
**Parameter:**
|
||||
- `csr` (string, erforderlich): Der CSR im PEM-Format, Base64-kodiert
|
||||
- `action` (string, erforderlich): Aktuell nur `"sign"` erlaubt
|
||||
- `validity_days` (integer, optional): Gültigkeitsdauer in Tagen (Standard: 365)
|
||||
|
||||
**Response (Erfolg):**
|
||||
```json
|
||||
{
|
||||
"id": "0202",
|
||||
"status": "success",
|
||||
"message": "CSR erfolgreich signiert",
|
||||
"certificate": "-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIRAK...\n-----END CERTIFICATE-----\n"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (Fehler):**
|
||||
```json
|
||||
{
|
||||
"error": "fehler beim Dekodieren des CSR: illegal base64 data"
|
||||
}
|
||||
```
|
||||
|
||||
**Status Codes:**
|
||||
- `200 OK` - CSR erfolgreich signiert
|
||||
- `400 Bad Request` - Ungültige Anfrage (fehlende Parameter, ungültiger CSR, etc.)
|
||||
- `405 Method Not Allowed` - Falsche HTTP-Methode
|
||||
- `500 Internal Server Error` - Server-Fehler beim Signieren
|
||||
|
||||
---
|
||||
|
||||
### 3. Zertifikat abrufen
|
||||
|
||||
Ruft ein signiertes Zertifikat anhand der Zertifikat-ID ab.
|
||||
|
||||
**Endpoint:** `GET /certificate/{id}`
|
||||
|
||||
**URL Parameter:**
|
||||
- `id` (string, erforderlich): Die Zertifikat-ID (aus der CSR-Response)
|
||||
|
||||
**Response (Erfolg):**
|
||||
```json
|
||||
{
|
||||
"id": "0202",
|
||||
"certificate": "-----BEGIN CERTIFICATE-----\nMIIDXTCCAkWgAwIBAgIRAK...\n-----END CERTIFICATE-----\n",
|
||||
"created_at": "2024-01-15T10:30:00Z"
|
||||
}
|
||||
```
|
||||
|
||||
**Response (Fehler):**
|
||||
```
|
||||
zertifikat mit ID 0202 nicht gefunden
|
||||
```
|
||||
|
||||
**Status Codes:**
|
||||
- `200 OK` - Zertifikat gefunden
|
||||
- `400 Bad Request` - Fehlende Zertifikat-ID
|
||||
- `404 Not Found` - Zertifikat nicht gefunden
|
||||
|
||||
---
|
||||
|
||||
### 4. Root-Zertifikat abrufen
|
||||
|
||||
Ruft das Root-Zertifikat der CA ab.
|
||||
|
||||
**Endpoint:** `GET /root`
|
||||
|
||||
**Response:**
|
||||
```
|
||||
-----BEGIN CERTIFICATE-----
|
||||
MIIDXTCCAkWgAwIBAgIRAK...
|
||||
-----END CERTIFICATE-----
|
||||
```
|
||||
|
||||
**Content-Type:** `application/x-pem-file`
|
||||
|
||||
**Status Codes:**
|
||||
- `200 OK` - Root-Zertifikat erfolgreich abgerufen
|
||||
|
||||
---
|
||||
|
||||
## Beispiel-Implementierungen
|
||||
|
||||
### Python
|
||||
|
||||
```python
|
||||
import requests
|
||||
import base64
|
||||
import json
|
||||
|
||||
CA_URL = "http://localhost:8088"
|
||||
|
||||
# 1. CSR aus Datei lesen und Base64 kodieren
|
||||
with open("request.csr", "rb") as f:
|
||||
csr_pem = f.read()
|
||||
csr_b64 = base64.b64encode(csr_pem).decode('utf-8')
|
||||
|
||||
# 2. CSR einreichen
|
||||
response = requests.post(
|
||||
f"{CA_URL}/csr",
|
||||
json={
|
||||
"csr": csr_b64,
|
||||
"action": "sign",
|
||||
"validity_days": 365
|
||||
},
|
||||
headers={"Content-Type": "application/json"}
|
||||
)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
cert_id = data["id"]
|
||||
certificate = data["certificate"]
|
||||
|
||||
# Zertifikat speichern
|
||||
with open("signed.crt", "w") as f:
|
||||
f.write(certificate)
|
||||
|
||||
print(f"Zertifikat-ID: {cert_id}")
|
||||
else:
|
||||
print(f"Fehler: {response.status_code} - {response.text}")
|
||||
|
||||
# 3. Zertifikat später abrufen
|
||||
cert_response = requests.get(f"{CA_URL}/certificate/{cert_id}")
|
||||
if cert_response.status_code == 200:
|
||||
cert_data = cert_response.json()
|
||||
print(f"Zertifikat erstellt am: {cert_data['created_at']}")
|
||||
```
|
||||
|
||||
### cURL
|
||||
|
||||
```bash
|
||||
# CSR einreichen
|
||||
CSR_B64=$(cat request.csr | base64 -w 0)
|
||||
|
||||
curl -X POST http://localhost:8088/csr \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "{
|
||||
\"csr\": \"$CSR_B64\",
|
||||
\"action\": \"sign\",
|
||||
\"validity_days\": 365
|
||||
}"
|
||||
|
||||
# Zertifikat abrufen
|
||||
curl http://localhost:8088/certificate/0202
|
||||
|
||||
# Root-Zertifikat abrufen
|
||||
curl http://localhost:8088/root > root.crt
|
||||
```
|
||||
|
||||
### JavaScript/Node.js
|
||||
|
||||
```javascript
|
||||
const axios = require('axios');
|
||||
const fs = require('fs');
|
||||
|
||||
const CA_URL = 'http://localhost:8088';
|
||||
|
||||
async function submitCSR(csrPath) {
|
||||
// CSR lesen und Base64 kodieren
|
||||
const csrPEM = fs.readFileSync(csrPath, 'utf8');
|
||||
const csrB64 = Buffer.from(csrPEM).toString('base64');
|
||||
|
||||
try {
|
||||
// CSR einreichen
|
||||
const response = await axios.post(`${CA_URL}/csr`, {
|
||||
csr: csrB64,
|
||||
action: 'sign',
|
||||
validity_days: 365
|
||||
});
|
||||
|
||||
const { id, certificate } = response.data;
|
||||
|
||||
// Zertifikat speichern
|
||||
fs.writeFileSync('signed.crt', certificate);
|
||||
|
||||
console.log(`Zertifikat-ID: ${id}`);
|
||||
return id;
|
||||
} catch (error) {
|
||||
console.error('Fehler:', error.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
async function getCertificate(certId) {
|
||||
try {
|
||||
const response = await axios.get(`${CA_URL}/certificate/${certId}`);
|
||||
return response.data;
|
||||
} catch (error) {
|
||||
console.error('Fehler:', error.response?.data || error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Verwendung
|
||||
submitCSR('request.csr')
|
||||
.then(certId => getCertificate(certId))
|
||||
.then(data => console.log('Zertifikat erstellt:', data.created_at))
|
||||
.catch(console.error);
|
||||
```
|
||||
|
||||
### Go
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
const CA_URL = "http://localhost:8088"
|
||||
|
||||
type CSRRequest struct {
|
||||
CSR string `json:"csr"`
|
||||
Action string `json:"action"`
|
||||
ValidityDays int `json:"validity_days"`
|
||||
}
|
||||
|
||||
type CSRResponse struct {
|
||||
ID string `json:"id"`
|
||||
Status string `json:"status"`
|
||||
Message string `json:"message"`
|
||||
Certificate string `json:"certificate"`
|
||||
}
|
||||
|
||||
func submitCSR(csrPath string) (string, error) {
|
||||
// CSR lesen
|
||||
csrPEM, err := ioutil.ReadFile(csrPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
// Base64 kodieren
|
||||
csrB64 := base64.StdEncoding.EncodeToString(csrPEM)
|
||||
|
||||
// Request erstellen
|
||||
reqBody := CSRRequest{
|
||||
CSR: csrB64,
|
||||
Action: "sign",
|
||||
ValidityDays: 365,
|
||||
}
|
||||
|
||||
jsonData, _ := json.Marshal(reqBody)
|
||||
|
||||
// HTTP Request
|
||||
resp, err := http.Post(CA_URL+"/csr", "application/json", bytes.NewBuffer(jsonData))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return "", fmt.Errorf("fehler: %s", string(body))
|
||||
}
|
||||
|
||||
var csrResp CSRResponse
|
||||
json.Unmarshal(body, &csrResp)
|
||||
|
||||
// Zertifikat speichern
|
||||
ioutil.WriteFile("signed.crt", []byte(csrResp.Certificate), 0644)
|
||||
|
||||
return csrResp.ID, nil
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## CSR-Format
|
||||
|
||||
Der CSR muss im PEM-Format vorliegen und Base64-kodiert übertragen werden.
|
||||
|
||||
**Beispiel CSR (PEM):**
|
||||
```
|
||||
-----BEGIN CERTIFICATE REQUEST-----
|
||||
MIICVjCCAT4CAQAwEjEQMA4GA1UEAwwHZXhhbXBsZTEwggEiMA0GCSqGSIb3DQEB
|
||||
...
|
||||
-----END CERTIFICATE REQUEST-----
|
||||
```
|
||||
|
||||
**Erstellung eines CSR:**
|
||||
```bash
|
||||
# Private Key generieren
|
||||
openssl genrsa -out private.key 2048
|
||||
|
||||
# CSR erstellen
|
||||
openssl req -new -key private.key -out request.csr \
|
||||
-subj "/CN=example.com/O=Example Org/C=DE"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fehlerbehandlung
|
||||
|
||||
Alle Fehler werden als HTTP-Status-Codes zurückgegeben:
|
||||
|
||||
- **400 Bad Request**: Ungültige Anfrage (fehlende/ungültige Parameter)
|
||||
- **404 Not Found**: Ressource nicht gefunden (z.B. Zertifikat-ID existiert nicht)
|
||||
- **405 Method Not Allowed**: Falsche HTTP-Methode verwendet
|
||||
- **500 Internal Server Error**: Server-seitiger Fehler
|
||||
|
||||
Fehlermeldungen werden im Response-Body als Text zurückgegeben.
|
||||
|
||||
---
|
||||
|
||||
## Wichtige Hinweise
|
||||
|
||||
1. **Zertifikat-Speicher**: Zertifikate werden nur im Speicher gehalten und gehen nach einem Server-Neustart verloren.
|
||||
|
||||
2. **Keine Authentifizierung**: Die API hat aktuell keine Authentifizierung. Für Produktionsumgebungen sollte dies hinzugefügt werden.
|
||||
|
||||
3. **CSR-Validierung**: Die CA validiert die CSR-Signatur, aber nicht den Inhalt des CSR.
|
||||
|
||||
4. **Serialnummern**: Jedes Zertifikat erhält eine eindeutige, automatisch inkrementierte Serialnummer.
|
||||
|
||||
5. **Gültigkeitsdauer**: Standardmäßig 365 Tage, kann über `validity_days` angepasst werden.
|
||||
|
||||
---
|
||||
|
||||
## Testen der API
|
||||
|
||||
Sie können die API mit dem bereitgestellten Beispiel-Skript testen:
|
||||
|
||||
```bash
|
||||
./example.sh
|
||||
```
|
||||
|
||||
Oder manuell mit cURL:
|
||||
|
||||
```bash
|
||||
# Health Check
|
||||
curl http://localhost:8088/health
|
||||
|
||||
# Root-Zertifikat
|
||||
curl http://localhost:8088/root
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user