diff --git a/sectigo_certificates.go b/cacerts.go similarity index 67% rename from sectigo_certificates.go rename to cacerts.go index a6b5931..5b2b0af 100644 --- a/sectigo_certificates.go +++ b/cacerts.go @@ -1,6 +1,40 @@ package main -const sectigoNew string = `-----BEGIN CERTIFICATE----- +const ( + sectigoRoot string = `-----BEGIN CERTIFICATE----- +MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD +Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw +HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY +MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp +YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa +ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz +SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf +iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X +ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3 +IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS +VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE +SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu ++Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt +8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L +HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt +zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P +AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c +mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ +YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52 +gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA +Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB +JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX +DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui +TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5 +dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65 +LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp +0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY +QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL +-----END CERTIFICATE-----` + + sectigoNew string = `-----BEGIN CERTIFICATE----- MIIGTDCCBDSgAwIBAgIQOXpmzCdWNi4NqofKbqvjsTANBgkqhkiG9w0BAQwFADBf MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw @@ -37,7 +71,7 @@ r8IWKIMxzxLPv5Kt3ePKcUdvkBU/smqujSczTzzSjIoR5QqQA6lN1ZRSnuHIWCvh JEltkYnTAH41QJ6SAWO66GrrUESwN/cgZzL4JLEqz1Y= -----END CERTIFICATE-----` -const sectigoOld string = `-----BEGIN CERTIFICATE----- + sectigoOld string = `-----BEGIN CERTIFICATE----- MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV @@ -72,3 +106,4 @@ LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K 00u/I5sUKUErmgQfky3xxzlIPK1aEn8= -----END CERTIFICATE-----` +) diff --git a/generator.go b/generator.go new file mode 100644 index 0000000..83c88a9 --- /dev/null +++ b/generator.go @@ -0,0 +1,26 @@ +package main + +import ( + "crypto/x509" + "log" + + "software.sslmate.com/src/go-pkcs12" +) + +func generatePassword(n int) string { + for i := range n { + log.Println(i) + } + return "DefaultPass" +} + +func generatePKCS12(pKey any, cert *x509.Certificate, caCerts []*x509.Certificate) (string, []byte) { + pfxPass := generatePassword(50) + + pfxData, err := pkcs12.Modern.Encode(pKey, cert, caCerts, pfxPass) + if err != nil { + return "Failed to create PFX with given data.", nil + } else { + return "PKCS12 generated seemingly succesfully.", pfxData + } +} diff --git a/go.mod b/go.mod index 74ae0e9..c84870e 100644 --- a/go.mod +++ b/go.mod @@ -2,7 +2,10 @@ module pfxgen go 1.24.6 -require fyne.io/fyne/v2 v2.7.1 +require ( + fyne.io/fyne/v2 v2.7.1 + software.sslmate.com/src/go-pkcs12 v0.6.0 +) require ( fyne.io/systray v1.11.1-0.20250603113521-ca66a66d8b58 // indirect @@ -32,6 +35,7 @@ require ( github.com/srwiley/rasterx v0.0.0-20220730225603-2ab79fcdd4ef // indirect github.com/stretchr/testify v1.11.1 // indirect github.com/yuin/goldmark v1.7.8 // indirect + golang.org/x/crypto v0.33.0 // indirect golang.org/x/image v0.24.0 // indirect golang.org/x/net v0.35.0 // indirect golang.org/x/sys v0.30.0 // indirect diff --git a/go.sum b/go.sum index ab682a5..f6d9f4c 100644 --- a/go.sum +++ b/go.sum @@ -65,6 +65,8 @@ github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/image v0.24.0 h1:AN7zRgVsbvmTfNyqIbbOraYL8mSwcKncEj8ofjgzcMQ= golang.org/x/image v0.24.0/go.mod h1:4b/ITuLfqYq1hqZcjofwctIhi7sZh2WaCjvsBNjjya8= golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= @@ -78,3 +80,5 @@ gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8X gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +software.sslmate.com/src/go-pkcs12 v0.6.0 h1:f3sQittAeF+pao32Vb+mkli+ZyT+VwKaD014qFGq6oU= +software.sslmate.com/src/go-pkcs12 v0.6.0/go.mod h1:Qiz0EyvDRJjjxGyUQa2cCNZn/wMyzrRJ/qcDXOQazLI= diff --git a/main.go b/main.go index 79af33c..7030a0c 100644 --- a/main.go +++ b/main.go @@ -13,11 +13,15 @@ import ( "fyne.io/fyne/v2/container" "fyne.io/fyne/v2/dialog" "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/storage" "fyne.io/fyne/v2/widget" ) var ( - windowSize fyne.Size = fyne.NewSize(600, 500) + windowSize fyne.Size = fyne.NewSize(700, 500) + + keyTextFilter []string = []string{".key", ".txt", ".pem"} + crtTextFilter []string = []string{".crt", ".cer", ".txt", ".pem"} ) func main() { @@ -42,8 +46,9 @@ func main() { r.Close() } }, w) - // Optionally set filters, title, etc. - // certDiag.SetFilter(...) + keyFilter := storage.NewExtensionFileFilter(keyTextFilter) + keyDiag.SetFilter(keyFilter) + keyDiag.Resize(windowSize) keyDiag.Show() }) @@ -58,6 +63,9 @@ func main() { r.Close() } }, w) + certFilter := storage.NewExtensionFileFilter(crtTextFilter) + certDiag.SetFilter(certFilter) + // Resize the dialog certDiag.Resize(windowSize) certDiag.Show() @@ -77,11 +85,11 @@ func main() { }) caRadio.SetSelected("New Sectigo (2025+)") // default - entry := widget.NewEntry() - entry.SetPlaceHolder("") - entry.Disable() + // Make a text grid to display text. + grid := widget.NewTextGrid() + grid.SetText("Status will appear here.") - actionBtn := widget.NewButton("Generate PKCS12 (pfx)", func() { + actionBtn := widget.NewButton("Generate", func() { files := []string{keyPath, certPath} var caCert string @@ -90,6 +98,7 @@ func main() { } else { caCert = sectigoOld } + rootCert := sectigoRoot allPresent := true if slices.Contains(files, "") { @@ -101,7 +110,42 @@ func main() { return } - entry.SetText(integrityCheckAndGo(keyPath, certPath, caCert)) + respText, pfxData := integrityCheckAndGo(keyPath, certPath, caCert, rootCert) + + log.Println(respText) + grid.SetText(respText) + + // Show Save File dialog immediately + svDialog := dialog.NewFileSave( + func(writer fyne.URIWriteCloser, err error) { + if err != nil { + dialog.ShowError(err, w) + return + } + if writer == nil { + // User cancelled + return + } + + _, writeErr := writer.Write(pfxData) + if writeErr != nil { + dialog.ShowError(writeErr, w) + return + } + + writer.Close() + + var dnText string = "PKCS file saved to: " + writer.URI().Path() + + log.Println(dnText) + grid.SetText(dnText) + }, w) + svDialog.Resize(windowSize) + + svDialog.SetFileName("certificate_store.pfx") + svDialog.SetFilter(storage.NewExtensionFileFilter([]string{".pfx"})) + + svDialog.Show() }) cancelBtn := widget.NewButton("Exit", func() { @@ -121,10 +165,11 @@ func main() { widget.NewLabel("Select relevant files."), container.New(layout.NewGridLayout(2), keyBtn, fileLabel1), container.New(layout.NewGridLayout(2), certBtn, fileLabel2), - layout.NewSpacer(), + widget.NewLabel("\n"), container.New(layout.NewGridLayout(2), radioLabel1, caRadio), - layout.NewSpacer(), // optional flexible space - entry, // just add the entry directly + layout.NewSpacer(), // optional flexible space + grid, // Add the referenced text grid container + widget.NewLabel(""), // Add empty line for space ) content := container.NewBorder( @@ -175,15 +220,15 @@ func parseX509(certData []byte) *x509.Certificate { return cert } -func integrityCheckAndGo(keyPath, certPath, caCertString string) string { +func integrityCheckAndGo(keyPath, certPath, caCertString, caRootString string) (string, []byte) { if _, err := os.Stat(keyPath); err != nil { fmt.Printf("Error checking Private Keyfile, %e", err) - return "Error..." + return "Error...", nil } if _, err := os.Stat(certPath); err != nil { fmt.Printf("Error checking Certificate file, %e", err) - return "Error..." + return "Error...", nil } keyData := readFile(keyPath) // Read the private key file (PEM/DER) @@ -192,6 +237,7 @@ func integrityCheckAndGo(keyPath, certPath, caCertString string) string { key := parsePrivateKey(keyData) // Convert bytes to Go private key object cert := parseX509(certData) // Convert bytes to Go x509.Certificate caCert := parseX509([]byte(caCertString)) + rootCert := parseX509([]byte(caRootString)) checkPublicKey(cert) // Print the information about the key @@ -201,9 +247,7 @@ func integrityCheckAndGo(keyPath, certPath, caCertString string) string { fmt.Println("Private key does NOT match certificate") } - return generatePKCS12(key, cert, caCert) -} + caCertList := []*x509.Certificate{caCert, rootCert} -func generatePKCS12(pKey any, cert, caCert *x509.Certificate) string { - return "Nice" + return generatePKCS12(key, cert, caCertList) }