feat: new features - version 1.0.0
This commit is contained in:
@@ -30,8 +30,8 @@ func generatePKCS12(pKey any, cert *x509.Certificate, caCerts []*x509.Certificat
|
||||
|
||||
pfxData, err := pkcs12.Modern.Encode(pKey, cert, caCerts, pfxPass)
|
||||
if err != nil {
|
||||
return "Failed to create PFX with given data.", nil, err
|
||||
return "", nil, err
|
||||
} else {
|
||||
return "PKCS generated succesfully, password: " + pfxPass, pfxData, nil
|
||||
return pfxPass, pfxData, nil
|
||||
}
|
||||
}
|
||||
|
||||
216
main.go
216
main.go
@@ -6,6 +6,7 @@ import (
|
||||
"image/color"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
certpair "pkcs-generator/modules/certpairs"
|
||||
"slices"
|
||||
|
||||
@@ -21,7 +22,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
windowSize fyne.Size = fyne.NewSize(700, 500)
|
||||
windowSize fyne.Size = fyne.NewSize(700, 600)
|
||||
|
||||
keyTextFilter []string = []string{".key", ".txt", ".pem"}
|
||||
crtTextFilter []string = []string{".crt", ".cer", ".txt", ".pem"}
|
||||
@@ -31,24 +32,44 @@ func main() {
|
||||
a := app.NewWithID("nl.systemec.pkcs-generator")
|
||||
a.Settings().SetTheme(theme.DefaultTheme())
|
||||
|
||||
w := a.NewWindow("Systemec PKCS-Generator")
|
||||
w := a.NewWindow("PKCS-Generator")
|
||||
w.Resize(windowSize)
|
||||
|
||||
var keyPath, certPath string
|
||||
var keyPath, certPath, caIssuer string
|
||||
var writePassDown, overwritePassDown bool
|
||||
|
||||
// Needs to be rendered early!
|
||||
// Certificate Intermediate selector
|
||||
// Basic in form but can easily be expanded.
|
||||
var caChoices = []string{"Sectigo Public Server Authentication CA DV R36", "Sectigo RSA Domain Validation Secure Server CA"}
|
||||
var sectigo2025 bool
|
||||
caRadio := widget.NewRadioGroup(caChoices, func(selected string) {
|
||||
switch selected {
|
||||
case "Sectigo Public Server Authentication CA DV R36":
|
||||
log.Println("Sectigo Public Server Authentication CA DV R36")
|
||||
sectigo2025 = true
|
||||
case "Sectigo RSA Domain Validation Secure Server CA":
|
||||
log.Println("Sectigo RSA Domain Validation Secure Server CA")
|
||||
sectigo2025 = false
|
||||
default: //Fallback
|
||||
sectigo2025 = true
|
||||
}
|
||||
})
|
||||
|
||||
// Labels to show selected filenames
|
||||
fileLabel1 := widget.NewLabel("No file selected")
|
||||
fileLabel2 := widget.NewLabel("No file selected")
|
||||
|
||||
radioLabel1 := widget.NewLabel("Select which Sectigo Intermediate")
|
||||
radioLabel1 := widget.NewLabel("If needed you can override the selection.\nOtherwise let the application decide.")
|
||||
|
||||
// Certificate Keyfile
|
||||
keyBtn := widget.NewButton("Upload Private Key File", func() {
|
||||
keyDiag := dialog.NewFileOpen(func(r fyne.URIReadCloser, err error) {
|
||||
defer r.Close()
|
||||
|
||||
if r != nil {
|
||||
fileLabel1.SetText(r.URI().Name())
|
||||
keyPath = r.URI().Path()
|
||||
r.Close()
|
||||
}
|
||||
}, w)
|
||||
keyFilter := storage.NewExtensionFileFilter(keyTextFilter)
|
||||
@@ -58,14 +79,34 @@ func main() {
|
||||
keyDiag.Show()
|
||||
})
|
||||
|
||||
keyWide := container.NewGridWrap(
|
||||
fyne.NewSize(400, 50),
|
||||
keyBtn,
|
||||
)
|
||||
|
||||
// Issuer entry
|
||||
issuerText := widget.NewLabel("Certificate issuer will appear here...")
|
||||
issuerText.Selectable = true
|
||||
|
||||
// Certificate file
|
||||
certBtn := widget.NewButton("Upload Certificate File", func() {
|
||||
// Use NewFileOpen to get the dialog object
|
||||
certDiag := dialog.NewFileOpen(func(r fyne.URIReadCloser, err error) {
|
||||
defer r.Close()
|
||||
|
||||
if r != nil {
|
||||
fileLabel2.SetText(r.URI().Name())
|
||||
certPath = r.URI().Path()
|
||||
r.Close()
|
||||
|
||||
certData := readFile(certPath)
|
||||
certObj := parseX509(certData)
|
||||
caIssuer = certObj.Issuer.CommonName
|
||||
log.Println("Issuer:", caIssuer)
|
||||
issuerText.SetText(caIssuer)
|
||||
|
||||
if slices.Contains(caChoices, caIssuer) {
|
||||
caRadio.SetSelected(caIssuer)
|
||||
}
|
||||
}
|
||||
}, w)
|
||||
certFilter := storage.NewExtensionFileFilter(crtTextFilter)
|
||||
@@ -76,31 +117,39 @@ func main() {
|
||||
certDiag.Show()
|
||||
})
|
||||
|
||||
// Certificate Intermediate selector
|
||||
// Basic in form but can easily be expanded.
|
||||
var sectigo2025 bool
|
||||
caRadio := widget.NewRadioGroup([]string{"New Sectigo (2025-03-22+)", "Old Sectigo (2025-03-22-)"}, func(selected string) {
|
||||
switch selected {
|
||||
case "New Sectigo (2025-03-22+)":
|
||||
sectigo2025 = true
|
||||
case "Old Sectigo (2025-03-22-)":
|
||||
sectigo2025 = false
|
||||
default: //Fallback
|
||||
sectigo2025 = true
|
||||
certWide := container.NewGridWrap(
|
||||
fyne.NewSize(400, 50),
|
||||
certBtn,
|
||||
)
|
||||
|
||||
// Render the overwrite checkfox first since I need its variable/object to disable/enable in the next checkbox (which is visually above this one)
|
||||
overwriteCheckBox := widget.NewCheck("Overwrite possible existing 'pkcs_password' file", func(checked bool) {
|
||||
if checked {
|
||||
log.Println("Checked box: overwrite if file exists.")
|
||||
overwritePassDown = true
|
||||
} else {
|
||||
log.Println("Unchecked box: not overwriting if file exists.")
|
||||
overwritePassDown = false
|
||||
}
|
||||
})
|
||||
caRadio.SetSelected("New Sectigo (2025+)") // default
|
||||
// Disable the checkbox by default since its reliant on the writeCheckBox
|
||||
overwriteCheckBox.Disable()
|
||||
|
||||
// Multiline entry
|
||||
textLabl := widget.NewLabel("Status will appear here...")
|
||||
textLabl.Selectable = true
|
||||
writeCheckBox := widget.NewCheck("Save password to file", func(checked bool) {
|
||||
if checked {
|
||||
log.Println("Checked box: saving to file.")
|
||||
writePassDown = true
|
||||
overwriteCheckBox.Enable()
|
||||
} else {
|
||||
log.Println("Unchecked box: not saving to file")
|
||||
writePassDown = false
|
||||
overwriteCheckBox.Disable()
|
||||
}
|
||||
})
|
||||
|
||||
border := canvas.NewRectangle(color.Transparent)
|
||||
border.StrokeColor = color.RGBA{255, 255, 255, 255}
|
||||
border.StrokeWidth = 2
|
||||
border.CornerRadius = 5
|
||||
|
||||
statusBox := container.NewStack(border, textLabl)
|
||||
// Status label, where pfx pass will appear
|
||||
statusText := widget.NewLabel("Status will appear here...")
|
||||
statusText.Selectable = true
|
||||
|
||||
actionBtn := widget.NewButton("Generate", func() {
|
||||
files := []string{keyPath, certPath}
|
||||
@@ -116,83 +165,127 @@ func main() {
|
||||
certPair = certpair.SectigoOldChain
|
||||
}
|
||||
|
||||
// Check if one of the filepaths is empty
|
||||
allPresent := true
|
||||
if slices.Contains(files, "") {
|
||||
allPresent = false
|
||||
}
|
||||
|
||||
// Check if all needed file/data is present
|
||||
if !allPresent {
|
||||
textLabl.SetText("One or more files missing!")
|
||||
statusText.SetText("One or more files missing!")
|
||||
log.Println("One or more files missing!")
|
||||
return
|
||||
}
|
||||
|
||||
respText, pfxData := integrityCheckAndGo(keyPath, certPath, certPair[1], certPair[0])
|
||||
// Generate the PKCS file with the given data
|
||||
pfxPass, pfxData := integrityCheckAndGo(keyPath, certPath, certPair[1], certPair[0])
|
||||
|
||||
if pfxData == nil {
|
||||
log.Println(respText)
|
||||
textLabl.SetText(respText)
|
||||
return
|
||||
// Check if the data returned is OK
|
||||
if len(pfxData) == 0 || pfxData == nil {
|
||||
log.Println("Something went wrong while creating the PKCS file...")
|
||||
statusText.SetText("Something went wrong while creating the PKCS file...")
|
||||
}
|
||||
|
||||
// Show Save File dialog immediately
|
||||
// Most important dialog next, saving the PKCS somewhere
|
||||
// We also need to declare some variables because otherwise theyd become out of scope
|
||||
var desiredPath string
|
||||
var defaultName string = "certificate_store.pfx"
|
||||
svDialog := dialog.NewFileSave(
|
||||
func(writer fyne.URIWriteCloser, err error) {
|
||||
defer writer.Close()
|
||||
|
||||
desiredPath = writer.URI().Path()
|
||||
desiredParentPath := filepath.Dir(desiredPath)
|
||||
|
||||
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
|
||||
_, err = writer.Write(pfxData)
|
||||
if err != nil {
|
||||
dialog.ShowError(err, w)
|
||||
}
|
||||
|
||||
writer.Close()
|
||||
var dnText string = "PKCS file saved to: " + desiredPath + "\nThe password for the generated pkcs file is:\n\n" + pfxPass
|
||||
|
||||
var dnText string = "\nPKCS file saved to: " + writer.URI().Path() + "\n\n" + respText + "\n"
|
||||
// Write down the PKCS password on the filesystem
|
||||
if writePassDown {
|
||||
wholePath := desiredParentPath + "/pkcs_password"
|
||||
var alreadyExists bool
|
||||
|
||||
textLabl.SetText(dnText)
|
||||
if _, err := os.Stat(wholePath); err == nil {
|
||||
alreadyExists = true
|
||||
} else if os.IsNotExist(err) {
|
||||
alreadyExists = false
|
||||
}
|
||||
|
||||
if alreadyExists && !overwritePassDown {
|
||||
log.Println("File already exists and overwrite checkbox is unchecked.")
|
||||
dnText += "\n\nCAREFUL! PKCS password was NOT written down. File exists! NOT OVERWRITING!"
|
||||
} else {
|
||||
log.Println("Writing PKCS password to: " + wholePath)
|
||||
err := os.WriteFile(wholePath, []byte(pfxPass), 0644)
|
||||
if err != nil {
|
||||
log.Println("Error writing file:", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
statusText.SetText(dnText)
|
||||
}, w)
|
||||
svDialog.Resize(windowSize)
|
||||
|
||||
svDialog.SetFileName("certificate_store.pfx")
|
||||
svDialog.SetFileName(defaultName)
|
||||
svDialog.SetFilter(storage.NewExtensionFileFilter([]string{".pfx"}))
|
||||
|
||||
svDialog.Show()
|
||||
})
|
||||
|
||||
actionWide := container.NewGridWrap(
|
||||
fyne.NewSize(200, 50),
|
||||
actionBtn,
|
||||
)
|
||||
|
||||
cancelBtn := widget.NewButton("Exit", func() {
|
||||
log.Println("Quitting...")
|
||||
os.Exit(0)
|
||||
a.Quit()
|
||||
})
|
||||
|
||||
exitWide := container.NewGridWrap(
|
||||
fyne.NewSize(200, 50),
|
||||
cancelBtn,
|
||||
)
|
||||
|
||||
// CREATE LAYOUTS
|
||||
|
||||
bottom := container.NewHBox(
|
||||
actionBtn, // left
|
||||
actionWide, // left
|
||||
layout.NewSpacer(), // flexible space
|
||||
cancelBtn, // right
|
||||
exitWide, // right
|
||||
)
|
||||
|
||||
centerContent := container.NewVBox(
|
||||
widget.NewLabel("Select relevant files."),
|
||||
container.New(layout.NewGridLayout(2), keyBtn, fileLabel1),
|
||||
container.New(layout.NewGridLayout(2), certBtn, fileLabel2),
|
||||
widget.NewLabel("\n"),
|
||||
container.New(layout.NewGridLayout(2), keyWide, fileLabel1),
|
||||
container.New(layout.NewGridLayout(2), certWide, fileLabel2),
|
||||
widget.NewLabel(""),
|
||||
issuerText,
|
||||
canvas.NewLine(color.Gray{Y: 128}),
|
||||
widget.NewLabel(""),
|
||||
container.New(layout.NewGridLayout(2), radioLabel1, caRadio),
|
||||
layout.NewSpacer(), // optional flexible space
|
||||
statusBox, // Add the referenced text container
|
||||
layout.NewSpacer(), // optional flexible space
|
||||
writeCheckBox,
|
||||
overwriteCheckBox,
|
||||
canvas.NewLine(color.Gray{Y: 128}),
|
||||
statusText, // Add the referenced text container
|
||||
widget.NewLabel(""), // Add empty line for space
|
||||
)
|
||||
|
||||
content := container.NewBorder(
|
||||
nil, // top
|
||||
widget.NewLabel("Select relevant files."), // top
|
||||
bottom, // bottom
|
||||
nil, nil, // left, right
|
||||
centerContent,
|
||||
@@ -253,9 +346,16 @@ func integrityCheckAndGo(keyPath, certPath, caRootString, caCertString string) (
|
||||
keyData := readFile(keyPath) // Read the private key file (PEM/DER)
|
||||
certData := readFile(certPath) // Read the certificate file (PEM/DER)
|
||||
|
||||
log.Println("Loading key")
|
||||
key := parsePrivateKey(keyData) // Convert bytes to Go private key object
|
||||
cert := parseX509(certData) // Convert bytes to Go x509.Certificate
|
||||
|
||||
log.Println("Loading certificate")
|
||||
cert := parseX509(certData) // Convert bytes to Go x509.Certificate
|
||||
|
||||
log.Println("Loading CA certificate")
|
||||
caCert := parseX509([]byte(caCertString))
|
||||
|
||||
log.Println("Loading ROOT certificate")
|
||||
rootCert := parseX509([]byte(caRootString))
|
||||
|
||||
checkPublicKey(cert) // Print the information about the key
|
||||
@@ -268,9 +368,9 @@ func integrityCheckAndGo(keyPath, certPath, caRootString, caCertString string) (
|
||||
|
||||
caCertList := []*x509.Certificate{caCert, rootCert}
|
||||
|
||||
msg, pfxData, err := generatePKCS12(key, cert, caCertList)
|
||||
pfxPass, pfxData, err := generatePKCS12(key, cert, caCertList)
|
||||
if err != nil {
|
||||
return msg, nil
|
||||
return "", nil
|
||||
}
|
||||
return msg, pfxData
|
||||
return pfxPass, pfxData
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user