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 }