package api import ( "crypto/rand" "crypto/rsa" "crypto/x509" "crypto/x509/pkix" "encoding/json" "encoding/pem" "errors" "fmt" "math/big" "net/http" "os" "scm/model" "time" "github.com/youmark/pkcs8" ) func CreateCert(w http.ResponseWriter, r *http.Request) { var requestData model.CreateCertificateRequest if err := json.NewDecoder(r.Body).Decode(&requestData); err != nil { http.Error(w, "invalid JSON format", http.StatusBadRequest) return } caCert, caKey, err := loadCertAndKey( fmt.Sprintf( "%s/%s/%s.crt", os.Getenv("CERTS_PATH"), "root", "TolaMironcenkoCA", ), fmt.Sprintf( "%s/%s/%s.key", os.Getenv("CERTS_PATH"), "root", "TolaMironcenkoCA", ), requestData.CAKeyPassword, ) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) fmt.Println("error loading certificate and key:", err) return } // TODO: Implement create certificate endpoint serverKey, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) fmt.Println("error generating server key:", err) return } serverCert, err := createServerCert(caCert, caKey, serverKey, requestData) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) fmt.Println("error creating server certificate:", err) return } _, err = os.Stat(fmt.Sprintf("%s/%s", os.Getenv("CERTS_PATH"), requestData.DNSNames[0])) if err == nil { http.Error(w, "certificate already exists", http.StatusConflict) fmt.Println("certificate already exists") return } else if os.IsNotExist(err) { err := os.Mkdir(fmt.Sprintf("%s/%s", os.Getenv("CERTS_PATH"), requestData.DNSNames[0]), 0755) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) fmt.Println("error creating directory:", err) return } } else { http.Error(w, err.Error(), http.StatusInternalServerError) fmt.Println("error checking certificate directory:", err) return } err = savePEM(fmt.Sprintf("%s/%s/%s.crt", os.Getenv("CERTS_PATH"), requestData.DNSNames[0], requestData.DNSNames[0]), "CERTIFICATE", serverCert) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) fmt.Println("error saving certificate:", err) return } err = savePEM(fmt.Sprintf("%s/%s/%s.key", os.Getenv("CERTS_PATH"), requestData.DNSNames[0], requestData.DNSNames[0]), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(serverKey)) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) fmt.Println("error saving private key:", err) return } fmt.Fprintf(w, "%s", `{"status": "success", "message": "Certificate created successfully"}`) } func createServerCert( caCert *x509.Certificate, caKey *rsa.PrivateKey, serverKey *rsa.PrivateKey, certdata model.CreateCertificateRequest, ) ([]byte, error) { // Шаблон серверного сертификата template := x509.Certificate{ SerialNumber: big.NewInt(time.Now().Unix()), Subject: pkix.Name{ Organization: certdata.OrganizationName, CommonName: certdata.CommonName, OrganizationalUnit: certdata.OrganizationUnit, }, NotBefore: time.Now(), NotAfter: time.Now().AddDate(1, 0, 0), // 1 год KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageKeyEncipherment, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, DNSNames: certdata.DNSNames, } // Создаем сертификат, подписанный CA return x509.CreateCertificate( rand.Reader, &template, caCert, &serverKey.PublicKey, caKey, ) } func loadCertAndKey(certFile, keyFile, password string) (*x509.Certificate, *rsa.PrivateKey, error) { fmt.Println(certFile, keyFile) // Загрузка корневого сертификата caCertPEM, err := os.ReadFile(certFile) if err != nil { return nil, nil, err } block, _ := pem.Decode(caCertPEM) if block == nil { return nil, nil, errors.New("failed to parse CA certificate PEM") } caCert, err := x509.ParseCertificate(block.Bytes) if err != nil { return nil, nil, err } // Загрузка зашифрованного приватного ключа keyPEM, err := os.ReadFile(keyFile) if err != nil { return nil, nil, err } block, _ = pem.Decode(keyPEM) if block == nil { return nil, nil, errors.New("failed to parse CA key PEM") } fmt.Print(block.Type) // Декодирование ключа с паролем decryptedKey, err := pkcs8.ParsePKCS8PrivateKey(block.Bytes, []byte(password)) if err != nil { return nil, nil, fmt.Errorf("failed to decrypt CA key: %v", err) } caKey, ok := decryptedKey.(*rsa.PrivateKey) if !ok { return nil, nil, err } return caCert, caKey, nil } func savePEM(filename, blockType string, data []byte) error { file, err := os.Create(filename) if err != nil { return err } defer file.Close() err = pem.Encode(file, &pem.Block{ Type: blockType, Bytes: data, }) if err != nil { return err } return nil }