From 7cab5ff9cb4536275a4a4ad927eb00e44e3eef5b Mon Sep 17 00:00:00 2001 From: DaanSelen Date: Fri, 21 Nov 2025 16:55:38 +0100 Subject: [PATCH] feat: add more code and features --- integrity.go | 44 +++++++ main.go | 256 +++++++++++++++++++++++++++------------- sectigo_certificates.go | 74 ++++++++++++ 3 files changed, 294 insertions(+), 80 deletions(-) create mode 100644 integrity.go create mode 100644 sectigo_certificates.go diff --git a/integrity.go b/integrity.go new file mode 100644 index 0000000..a6fd695 --- /dev/null +++ b/integrity.go @@ -0,0 +1,44 @@ +package main + +import ( + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/x509" + "fmt" + "log" +) + +func checkPublicKey(cert *x509.Certificate) { + switch pub := cert.PublicKey.(type) { + + case *rsa.PublicKey: + fmt.Println("RSA key:", pub.N.BitLen(), "bits") + case *ecdsa.PublicKey: + fmt.Println("ECDSA key:", pub.Curve.Params().Name) + case ed25519.PublicKey: + fmt.Println("Ed25519 key") + default: + log.Fatal("Unsupported public key type") + } +} + +func checkCertKeyPair(certPub any, priv any) bool { + switch pub := certPub.(type) { + + case *rsa.PublicKey: + privRSA, ok := priv.(*rsa.PrivateKey) + return ok && pub.N.Cmp(privRSA.N) == 0 && pub.E == privRSA.E + + case *ecdsa.PublicKey: + privECDSA, ok := priv.(*ecdsa.PrivateKey) + return ok && pub.X.Cmp(privECDSA.X) == 0 && pub.Y.Cmp(privECDSA.Y) == 0 + + case ed25519.PublicKey: + privEd, ok := priv.(ed25519.PrivateKey) + return ok && pub.Equal(privEd.Public().(ed25519.PublicKey)) + + default: + return false + } +} diff --git a/main.go b/main.go index 2572559..c7d5809 100644 --- a/main.go +++ b/main.go @@ -1,99 +1,195 @@ package main import ( - "fmt" - "os" - "fyne.io/fyne/v2" - "fyne.io/fyne/v2/app" - "fyne.io/fyne/v2/container" - "fyne.io/fyne/v2/dialog" - "fyne.io/fyne/v2/widget" - "fyne.io/fyne/v2/layout" + "crypto/x509" + "encoding/pem" + "fmt" + "log" + "os" + "slices" + + "fyne.io/fyne/v2" + "fyne.io/fyne/v2/app" + "fyne.io/fyne/v2/container" + "fyne.io/fyne/v2/dialog" + "fyne.io/fyne/v2/layout" + "fyne.io/fyne/v2/widget" ) func main() { - a := app.New() - w := a.NewWindow("Upload 3 Files") - w.Resize(fyne.NewSize(800, 400)) + a := app.NewWithID("nl.systemec.pfxgen") + w := a.NewWindow("Systemec PKCS12-Generator") + w.Resize(fyne.NewSize(600, 400)) - var file1Path, file2Path, file3Path string + var keyPath, certPath string - // Labels to show selected filenames - fileLabel1 := widget.NewLabel("No file selected") - fileLabel2 := widget.NewLabel("No file selected") - fileLabel3 := widget.NewLabel("No file selected") + // Labels to show selected filenames + fileLabel1 := widget.NewLabel("No file selected") + fileLabel2 := widget.NewLabel("No file selected") - // Button 1 - btn1 := widget.NewButton("Upload Certificate Private Key File", func() { - dialog.ShowFileOpen(func(r fyne.URIReadCloser, err error) { - if r != nil { - fileLabel1.SetText(r.URI().Name()) - file1Path = r.URI().Path() - } - }, w) - }) + radioLabel1 := widget.NewLabel("Select which Sectigo Intermediate") - // Button 2 - btn2 := widget.NewButton("Upload Certificate File", func() { - dialog.ShowFileOpen(func(r fyne.URIReadCloser, err error) { - if r != nil { - fileLabel2.SetText(r.URI().Name()) - file2Path = r.URI().Path() - } - }, w) - }) + // Certificate Keyfile + btn1 := widget.NewButton("Upload Private Key File", func() { + dialog.ShowFileOpen(func(r fyne.URIReadCloser, err error) { + if r != nil { + fileLabel1.SetText(r.URI().Name()) + keyPath = r.URI().Path() + } + }, w) + }) - // Button 3 - btn3 := widget.NewButton("Upload Certificate Intermediate File", func() { - dialog.ShowFileOpen(func(r fyne.URIReadCloser, err error) { - if r != nil { - fileLabel3.SetText(r.URI().Name()) - file3Path = r.URI().Path() - } - }, w) - }) + // Certificate file + btn2 := widget.NewButton("Upload Certificate File", func() { + dialog.ShowFileOpen(func(r fyne.URIReadCloser, err error) { + if r != nil { + fileLabel2.SetText(r.URI().Name()) + certPath = r.URI().Path() + } + }, w) + }) - goBtn := widget.NewButton("Go", func() { - fmt.Println("Go button clicked") - files := []string{file1Path, file2Path, file3Path} + // Certificate Intermediate + var newSectigoSelected bool + caRadio := widget.NewRadioGroup([]string{"New Sectigo (2025+)", "Old Sectigo (2025-)"}, func(selected string) { + switch selected { + case "New Sectigo (2025+)": + newSectigoSelected = true + case "Old Sectigo (2025-)": + newSectigoSelected = false + default: //Fallback + newSectigoSelected = true + } + }) + caRadio.SetSelected("New Sectigo (2025+)") // default - allPresent := true - for _, f := range files { - if f == "" { - allPresent = false - break - } - } + entry := widget.NewEntry() + entry.SetPlaceHolder("") + entry.Disable() - if !allPresent { - fmt.Println("One or more files missing!") - return - } + actionBtn := widget.NewButton("Generate PKCS12 (pfx)", func() { + files := []string{keyPath, certPath} - for i, f := range files { - data, err := os.ReadFile(f) - if err != nil { - fmt.Printf("Error reading file %d (%s): %v\n", i+1, f, err) - continue - } + var caCert string + if newSectigoSelected { + caCert = sectigoNew + } else { + caCert = sectigoOld + } - fmt.Printf("Contents of file %d (%s):\n%s\n\n", i+1, f, string(data)) - } - }) + allPresent := true + if slices.Contains(files, "") { + allPresent = false + } - content := container.NewBorder( - nil, // top - goBtn, // bottom - nil, nil, // left, right - container.NewVBox( // center content - widget.NewLabel("Select 3 files:"), - container.NewHBox(btn1, fileLabel1), - container.NewHBox(btn2, fileLabel2), - container.NewHBox(btn3, fileLabel3), - layout.NewSpacer(), // adds flexible space - ), - ) + if !allPresent { + fmt.Println("One or more files missing!") + return + } - w.SetContent(content) - w.ShowAndRun() + entry.SetText(integrityCheckAndGo(keyPath, certPath, caCert)) + }) + + cancelBtn := widget.NewButton("Exit", func() { + fmt.Println("Quitting...") + os.Exit(0) + }) + + // CREATE LAYOUTS + + bottom := container.NewHBox( + actionBtn, // left + layout.NewSpacer(), // flexible space + cancelBtn, // right + ) + + centerContent := container.NewVBox( + widget.NewLabel("Select relevant files."), + container.New(layout.NewGridLayout(2), btn1, fileLabel1), + container.New(layout.NewGridLayout(2), btn2, fileLabel2), + layout.NewSpacer(), + container.New(layout.NewGridLayout(2), radioLabel1, caRadio), + layout.NewSpacer(), // optional flexible space + entry, // just add the entry directly + ) + + content := container.NewBorder( + nil, // top + bottom, // bottom + nil, nil, // left, right + centerContent, + ) + + w.SetContent(content) + w.ShowAndRun() +} + +func readFile(path string) []byte { + rawData, err := os.ReadFile(path) + if err != nil { + fmt.Printf("Error reading contents of %s, %e", path, err) + return nil + } else { + return rawData + } +} + +func parsePrivateKey(keyData []byte) any { + block, _ := pem.Decode(keyData) + if block == nil { + log.Fatal("failed to decode key PEM") + } + + privateKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) + if err != nil { + log.Fatal(err) + } + + return privateKey +} + +func parseX509(certData []byte) *x509.Certificate { + block, _ := pem.Decode(certData) + if block == nil { + log.Fatal("failed to parse PEM block") + } + + cert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + log.Fatal(err) + } + return cert +} + +func integrityCheckAndGo(keyPath, certPath, caCertString string) string { + if _, err := os.Stat(keyPath); err != nil { + fmt.Printf("Error checking Private Keyfile, %e", err) + return "Error..." + } + + if _, err := os.Stat(certPath); err != nil { + fmt.Printf("Error checking Certificate file, %e", err) + return "Error..." + } + + keyData := readFile(keyPath) // Read the private key file (PEM/DER) + certData := readFile(certPath) // Read the certificate file (PEM/DER) + + key := parsePrivateKey(keyData) // Convert bytes to Go private key object + cert := parseX509(certData) // Convert bytes to Go x509.Certificate + caCert := parseX509([]byte(caCertString)) + + checkPublicKey(cert) // Print the information about the key + + if checkCertKeyPair(cert.PublicKey, key) { + fmt.Println("Private key matches certificate") + } else { + fmt.Println("Private key does NOT match certificate") + } + + return generatePKCS12(key, cert, caCert) +} + +func generatePKCS12(pKey any, cert, caCert *x509.Certificate) string { + return "Nice" } diff --git a/sectigo_certificates.go b/sectigo_certificates.go new file mode 100644 index 0000000..a6b5931 --- /dev/null +++ b/sectigo_certificates.go @@ -0,0 +1,74 @@ +package main + +const sectigoNew string = `-----BEGIN CERTIFICATE----- +MIIGTDCCBDSgAwIBAgIQOXpmzCdWNi4NqofKbqvjsTANBgkqhkiG9w0BAQwFADBf +MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD +Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw +HhcNMjEwMzIyMDAwMDAwWhcNMzYwMzIxMjM1OTU5WjBgMQswCQYDVQQGEwJHQjEY +MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFB1Ymxp +YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gQ0EgRFYgUjM2MIIBojANBgkqhkiG9w0B +AQEFAAOCAY8AMIIBigKCAYEAljZf2HIz7+SPUPQCQObZYcrxLTHYdf1ZtMRe7Yeq +RPSwygz16qJ9cAWtWNTcuICc++p8Dct7zNGxCpqmEtqifO7NvuB5dEVexXn9RFFH +12Hm+NtPRQgXIFjx6MSJcNWuVO3XGE57L1mHlcQYj+g4hny90aFh2SCZCDEVkAja +EMMfYPKuCjHuuF+bzHFb/9gV8P9+ekcHENF2nR1efGWSKwnfG5RawlkaQDpRtZTm +M64TIsv/r7cyFO4nSjs1jLdXYdz5q3a4L0NoabZfbdxVb+CUEHfB0bpulZQtH1Rv +38e/lIdP7OTTIlZh6OYL6NhxP8So0/sht/4J9mqIGxRFc0/pC8suja+wcIUna0HB +pXKfXTKpzgis+zmXDL06ASJf5E4A2/m+Hp6b84sfPAwQ766rI65mh50S0Di9E3Pn +2WcaJc+PILsBmYpgtmgWTR9eV9otfKRUBfzHUHcVgarub/XluEpRlTtZudU5xbFN +xx/DgMrXLUAPaI60fZ6wA+PTAgMBAAGjggGBMIIBfTAfBgNVHSMEGDAWgBRWc1hk +lfmSGrASKgRieaFAFYghSTAdBgNVHQ4EFgQUaMASFhgOr872h6YyV6NGUV3LBycw +DgYDVR0PAQH/BAQDAgGGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0lBBYwFAYI +KwYBBQUHAwEGCCsGAQUFBwMCMBsGA1UdIAQUMBIwBgYEVR0gADAIBgZngQwBAgEw +VAYDVR0fBE0wSzBJoEegRYZDaHR0cDovL2NybC5zZWN0aWdvLmNvbS9TZWN0aWdv +UHVibGljU2VydmVyQXV0aGVudGljYXRpb25Sb290UjQ2LmNybDCBhAYIKwYBBQUH +AQEEeDB2ME8GCCsGAQUFBzAChkNodHRwOi8vY3J0LnNlY3RpZ28uY29tL1NlY3Rp +Z29QdWJsaWNTZXJ2ZXJBdXRoZW50aWNhdGlvblJvb3RSNDYucDdjMCMGCCsGAQUF +BzABhhdodHRwOi8vb2NzcC5zZWN0aWdvLmNvbTANBgkqhkiG9w0BAQwFAAOCAgEA +YtOC9Fy+TqECFw40IospI92kLGgoSZGPOSQXMBqmsGWZUQ7rux7cj1du6d9rD6C8 +ze1B2eQjkrGkIL/OF1s7vSmgYVafsRoZd/IHUrkoQvX8FZwUsmPu7amgBfaY3g+d +q1x0jNGKb6I6Bzdl6LgMD9qxp+3i7GQOnd9J8LFSietY6Z4jUBzVoOoz8iAU84OF +h2HhAuiPw1ai0VnY38RTI+8kepGWVfGxfBWzwH9uIjeooIeaosVFvE8cmYUB4TSH +5dUyD0jHct2+8ceKEtIoFU/FfHq/mDaVnvcDCZXtIgitdMFQdMZaVehmObyhRdDD +4NQCs0gaI9AAgFj4L9QtkARzhQLNyRf87Kln+YU0lgCGr9HLg3rGO8q+Y4ppLsOd +unQZ6ZxPNGIfOApbPVf5hCe58EZwiWdHIMn9lPP6+F404y8NNugbQixBber+x536 +WrZhFZLjEkhp7fFXf9r32rNPfb74X/U90Bdy4lzp3+X1ukh1BuMxA/EEhDoTOS3l +7ABvc7BYSQubQ2490OcdkIzUh3ZwDrakMVrbaTxUM2p24N6dB+ns2zptWCva6jzW +r8IWKIMxzxLPv5Kt3ePKcUdvkBU/smqujSczTzzSjIoR5QqQA6lN1ZRSnuHIWCvh +JEltkYnTAH41QJ6SAWO66GrrUESwN/cgZzL4JLEqz1Y= +-----END CERTIFICATE-----` + +const sectigoOld string = `-----BEGIN CERTIFICATE----- +MIIGEzCCA/ugAwIBAgIQfVtRJrR2uhHbdBYLvFMNpzANBgkqhkiG9w0BAQwFADCB +iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl +cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV +BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTgx +MTAyMDAwMDAwWhcNMzAxMjMxMjM1OTU5WjCBjzELMAkGA1UEBhMCR0IxGzAZBgNV +BAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEYMBYGA1UE +ChMPU2VjdGlnbyBMaW1pdGVkMTcwNQYDVQQDEy5TZWN0aWdvIFJTQSBEb21haW4g +VmFsaWRhdGlvbiBTZWN1cmUgU2VydmVyIENBMIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA1nMz1tc8INAA0hdFuNY+B6I/x0HuMjDJsGz99J/LEpgPLT+N +TQEMgg8Xf2Iu6bhIefsWg06t1zIlk7cHv7lQP6lMw0Aq6Tn/2YHKHxYyQdqAJrkj +eocgHuP/IJo8lURvh3UGkEC0MpMWCRAIIz7S3YcPb11RFGoKacVPAXJpz9OTTG0E +oKMbgn6xmrntxZ7FN3ifmgg0+1YuWMQJDgZkW7w33PGfKGioVrCSo1yfu4iYCBsk +Haswha6vsC6eep3BwEIc4gLw6uBK0u+QDrTBQBbwb4VCSmT3pDCg/r8uoydajotY +uK3DGReEY+1vVv2Dy2A0xHS+5p3b4eTlygxfFQIDAQABo4IBbjCCAWowHwYDVR0j +BBgwFoAUU3m/WqorSs9UgOHYm8Cd8rIDZsswHQYDVR0OBBYEFI2MXsRUrYrhd+mb ++ZsF4bgBjWHhMA4GA1UdDwEB/wQEAwIBhjASBgNVHRMBAf8ECDAGAQH/AgEAMB0G +A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAbBgNVHSAEFDASMAYGBFUdIAAw +CAYGZ4EMAQIBMFAGA1UdHwRJMEcwRaBDoEGGP2h0dHA6Ly9jcmwudXNlcnRydXN0 +LmNvbS9VU0VSVHJ1c3RSU0FDZXJ0aWZpY2F0aW9uQXV0aG9yaXR5LmNybDB2Bggr +BgEFBQcBAQRqMGgwPwYIKwYBBQUHMAKGM2h0dHA6Ly9jcnQudXNlcnRydXN0LmNv +bS9VU0VSVHJ1c3RSU0FBZGRUcnVzdENBLmNydDAlBggrBgEFBQcwAYYZaHR0cDov +L29jc3AudXNlcnRydXN0LmNvbTANBgkqhkiG9w0BAQwFAAOCAgEAMr9hvQ5Iw0/H +ukdN+Jx4GQHcEx2Ab/zDcLRSmjEzmldS+zGea6TvVKqJjUAXaPgREHzSyrHxVYbH +7rM2kYb2OVG/Rr8PoLq0935JxCo2F57kaDl6r5ROVm+yezu/Coa9zcV3HAO4OLGi +H19+24rcRki2aArPsrW04jTkZ6k4Zgle0rj8nSg6F0AnwnJOKf0hPHzPE/uWLMUx +RP0T7dWbqWlod3zu4f+k+TY4CFM5ooQ0nBnzvg6s1SQ36yOoeNDT5++SR2RiOSLv +xvcRviKFxmZEJCaOEDKNyJOuB56DPi/Z+fVGjmO+wea03KbNIaiGCpXZLoUmGv38 +sbZXQm2V0TP2ORQGgkE49Y9Y3IBbpNV9lXj9p5v//cWoaasm56ekBYdbqbe4oyAL +l6lFhd2zi+WJN44pDfwGF/Y4QA5C5BIG+3vzxhFoYt/jmPQT2BVPi7Fp2RBgvGQq +6jG35LWjOhSbJuMLe/0CjraZwTiXWTb2qHSihrZe68Zk6s+go/lunrotEbaGmAhY +LcmsJWTyXnW0OMGuf1pGg+pRyrbxmRE1a6Vqe8YAsOf4vmSyrcjC8azjUeqkk+B5 +yOGBQMkKW+ESPMFgKuOXwIlCypTPRpgSabuY0MLTDXJLR27lk8QyKGOHQ+SwMj4K +00u/I5sUKUErmgQfky3xxzlIPK1aEn8= +-----END CERTIFICATE-----`