pkiapi/internal/api/certificates.go

185 lines
5.0 KiB
Go

package api
import (
"encoding/base64"
"net/http"
"github.com/gin-gonic/gin"
"github.com/google/uuid"
"github.com/stef/pkiapi/internal/pki"
"github.com/stef/pkiapi/internal/storage"
)
// CreateCertificateRequest représente la requête de création de certificat
type CreateCertificateRequest struct {
Subject string `json:"subject" binding:"required"`
ValidityDays int `json:"validity_days" binding:"required,min=1,max=3650"`
}
// CertificateResponse représente la réponse avec les données du certificat
type CertificateResponse struct {
ID string `json:"id"`
Subject string `json:"subject"`
Issuer string `json:"issuer"`
NotBefore string `json:"not_before"`
NotAfter string `json:"not_after"`
SerialNumber string `json:"serial_number"`
Certificate string `json:"certificate"` // Base64 encoded
Revoked bool `json:"revoked"`
}
// certificateStore est un store global pour les certificats
var certificateStore storage.CertificateStore
// InitCertificateStore initialise le store pour les certificats
func InitCertificateStore(store storage.CertificateStore) {
certificateStore = store
}
// CreateCertificate crée un nouveau certificat auto-signé
func CreateCertificate(c *gin.Context) {
var req CreateCertificateRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Générer le certificat
cert, err := pki.GenerateCertificate(req.Subject, req.ValidityDays)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur génération certificat"})
return
}
// Générer un ID unique
certID := uuid.New().String()
cert.ID = certID
// Sauvegarder le certificat
if err := certificateStore.SaveCertificate(certID, cert); err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "erreur sauvegarde certificat"})
return
}
// Récupérer l'utilisateur depuis le contexte JWT
userID, _ := c.Get("user_id")
// Retourner la réponse
response := CertificateResponse{
ID: certID,
Subject: cert.Subject,
Issuer: cert.Issuer,
NotBefore: cert.NotBefore.Format("2006-01-02T15:04:05Z"),
NotAfter: cert.NotAfter.Format("2006-01-02T15:04:05Z"),
Revoked: false,
}
if cert.Cert != nil {
response.SerialNumber = cert.Cert.SerialNumber.String()
response.Certificate = base64.StdEncoding.EncodeToString(cert.Cert.Raw)
}
c.JSON(http.StatusCreated, gin.H{
"certificate": response,
"created_by": userID,
})
}
// ListCertificates retourne tous les certificats
func ListCertificates(c *gin.Context) {
certs := certificateStore.ListCertificates()
var responses []CertificateResponse
for _, cert := range certs {
response := CertificateResponse{
ID: cert.ID,
Subject: cert.Subject,
Issuer: cert.Issuer,
NotBefore: cert.NotBefore.Format("2006-01-02T15:04:05Z"),
NotAfter: cert.NotAfter.Format("2006-01-02T15:04:05Z"),
Revoked: cert.Revoked,
}
if cert.Cert != nil {
response.SerialNumber = cert.Cert.SerialNumber.String()
}
responses = append(responses, response)
}
c.JSON(http.StatusOK, gin.H{"certificates": responses})
}
// GetCertificate retourne un certificat par ID
func GetCertificate(c *gin.Context) {
id := c.Param("id")
cert, err := certificateStore.GetCertificate(id)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "certificat non trouvé"})
return
}
response := CertificateResponse{
ID: cert.ID,
Subject: cert.Subject,
Issuer: cert.Issuer,
NotBefore: cert.NotBefore.Format("2006-01-02T15:04:05Z"),
NotAfter: cert.NotAfter.Format("2006-01-02T15:04:05Z"),
Revoked: cert.Revoked,
}
if cert.Cert != nil {
response.SerialNumber = cert.Cert.SerialNumber.String()
response.Certificate = base64.StdEncoding.EncodeToString(cert.Cert.Raw)
}
c.JSON(http.StatusOK, gin.H{"certificate": response})
}
// RevokeCertificate révoque un certificat
func RevokeCertificate(c *gin.Context) {
var req struct {
CertificateID string `json:"certificate_id" binding:"required"`
Reason string `json:"reason"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
cert, err := certificateStore.GetCertificate(req.CertificateID)
if err != nil {
c.JSON(http.StatusNotFound, gin.H{"error": "certificat non trouvé"})
return
}
cert.Revoked = true
certificateStore.SaveCertificate(req.CertificateID, cert)
c.JSON(http.StatusOK, gin.H{
"message": "certificat révoqué",
"id": req.CertificateID,
"reason": req.Reason,
})
}
// GetCRL retourne la liste de révocation
func GetCRL(c *gin.Context) {
certs := certificateStore.ListCertificates()
var revokedCerts []gin.H
for _, cert := range certs {
if cert.Revoked && cert.Cert != nil {
revokedCerts = append(revokedCerts, gin.H{
"serial_number": cert.Cert.SerialNumber.String(),
"subject": cert.Subject,
})
}
}
c.JSON(http.StatusOK, gin.H{
"crl": revokedCerts,
"version": 1,
})
}