237 lines
5.9 KiB
Go
237 lines
5.9 KiB
Go
package pki
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/rsa"
|
|
"crypto/x509"
|
|
"crypto/x509/pkix"
|
|
"math/big"
|
|
"time"
|
|
)
|
|
|
|
// Certificate représente un certificat X.509
|
|
type Certificate struct {
|
|
ID string
|
|
Subject string
|
|
Issuer string
|
|
NotBefore time.Time
|
|
NotAfter time.Time
|
|
PublicKey *rsa.PublicKey
|
|
PrivateKey *rsa.PrivateKey // Stocké pour les CAs
|
|
Cert *x509.Certificate
|
|
Revoked bool
|
|
IsCA bool // True si c'est une autorité de certification
|
|
}
|
|
|
|
// GenerateCertificate crée un nouveau certificat auto-signé
|
|
func GenerateCertificate(subject string, validityDays int) (*Certificate, error) {
|
|
// Générer une clé RSA
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Créer le certificat
|
|
serialNumber, _ := rand.Int(rand.Reader, big.NewInt(1000000))
|
|
notBefore := time.Now()
|
|
notAfter := notBefore.AddDate(0, 0, validityDays)
|
|
|
|
cert := &x509.Certificate{
|
|
SerialNumber: serialNumber,
|
|
Subject: pkix.Name{
|
|
CommonName: subject,
|
|
},
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
|
}
|
|
|
|
// Auto-signer le certificat
|
|
certBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, &privateKey.PublicKey, privateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
parsedCert, err := x509.ParseCertificate(certBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Certificate{
|
|
Subject: subject,
|
|
Issuer: subject,
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
PublicKey: &privateKey.PublicKey,
|
|
PrivateKey: privateKey,
|
|
Cert: parsedCert,
|
|
Revoked: false,
|
|
IsCA: false,
|
|
}, nil
|
|
}
|
|
|
|
// GenerateCA crée une nouvelle autorité de certification
|
|
func GenerateCA(subject string, validityDays int) (*Certificate, error) {
|
|
// Générer une clé RSA
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Créer le certificat CA
|
|
serialNumber, _ := rand.Int(rand.Reader, big.NewInt(1000000000))
|
|
notBefore := time.Now()
|
|
notAfter := notBefore.AddDate(0, 0, validityDays)
|
|
|
|
cert := &x509.Certificate{
|
|
SerialNumber: serialNumber,
|
|
Subject: pkix.Name{
|
|
CommonName: subject,
|
|
},
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
BasicConstraintsValid: true,
|
|
IsCA: true,
|
|
MaxPathLen: -1, // Pas de limite de chaîne
|
|
}
|
|
|
|
// Auto-signer le certificat CA
|
|
certBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, &privateKey.PublicKey, privateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
parsedCert, err := x509.ParseCertificate(certBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Certificate{
|
|
Subject: subject,
|
|
Issuer: subject,
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
PublicKey: &privateKey.PublicKey,
|
|
PrivateKey: privateKey,
|
|
Cert: parsedCert,
|
|
Revoked: false,
|
|
IsCA: true,
|
|
}, nil
|
|
}
|
|
|
|
// SignCertificate signe un certificat avec une CA
|
|
func SignCertificate(caCert *Certificate, subject string, validityDays int) (*Certificate, error) {
|
|
if !caCert.IsCA {
|
|
return nil, ErrNotACA
|
|
}
|
|
|
|
if caCert.PrivateKey == nil {
|
|
return nil, ErrMissingPrivateKey
|
|
}
|
|
|
|
// Générer une clé RSA pour le nouveau certificat
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Créer le certificat à signer
|
|
serialNumber, _ := rand.Int(rand.Reader, big.NewInt(1000000000))
|
|
notBefore := time.Now()
|
|
notAfter := notBefore.AddDate(0, 0, validityDays)
|
|
|
|
cert := &x509.Certificate{
|
|
SerialNumber: serialNumber,
|
|
Subject: pkix.Name{
|
|
CommonName: subject,
|
|
},
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
|
Issuer: caCert.Cert.Subject,
|
|
}
|
|
|
|
// Signer le certificat avec la clé privée de la CA
|
|
certBytes, err := x509.CreateCertificate(rand.Reader, cert, caCert.Cert, &privateKey.PublicKey, caCert.PrivateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
parsedCert, err := x509.ParseCertificate(certBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Certificate{
|
|
Subject: subject,
|
|
Issuer: caCert.Subject,
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
PublicKey: &privateKey.PublicKey,
|
|
PrivateKey: privateKey,
|
|
Cert: parsedCert,
|
|
Revoked: false,
|
|
IsCA: false,
|
|
}, nil
|
|
}
|
|
|
|
// SignSubCA signe une CA intermédiaire avec une CA parent
|
|
func SignSubCA(parentCA *Certificate, subject string, validityDays int) (*Certificate, error) {
|
|
if !parentCA.IsCA {
|
|
return nil, ErrNotACA
|
|
}
|
|
|
|
if parentCA.PrivateKey == nil {
|
|
return nil, ErrMissingPrivateKey
|
|
}
|
|
|
|
// Générer une clé RSA pour la sub-CA
|
|
privateKey, err := rsa.GenerateKey(rand.Reader, 2048)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Créer le certificat CA intermédiaire
|
|
serialNumber, _ := rand.Int(rand.Reader, big.NewInt(1000000000))
|
|
notBefore := time.Now()
|
|
notAfter := notBefore.AddDate(0, 0, validityDays)
|
|
|
|
subCA := &x509.Certificate{
|
|
SerialNumber: serialNumber,
|
|
Subject: pkix.Name{
|
|
CommonName: subject,
|
|
},
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
|
|
BasicConstraintsValid: true,
|
|
IsCA: true,
|
|
MaxPathLen: 0, // Limite la chaîne : cette CA ne peut pas signer d'autres CAs
|
|
Issuer: parentCA.Cert.Subject,
|
|
}
|
|
|
|
// Signer le certificat CA avec la clé privée du parent
|
|
certBytes, err := x509.CreateCertificate(rand.Reader, subCA, parentCA.Cert, &privateKey.PublicKey, parentCA.PrivateKey)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
parsedCert, err := x509.ParseCertificate(certBytes)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &Certificate{
|
|
Subject: subject,
|
|
Issuer: parentCA.Subject,
|
|
NotBefore: notBefore,
|
|
NotAfter: notAfter,
|
|
PublicKey: &privateKey.PublicKey,
|
|
PrivateKey: privateKey,
|
|
Cert: parsedCert,
|
|
Revoked: false,
|
|
IsCA: true,
|
|
}, nil
|
|
}
|