From 02c0c1216f9ec4e26d69853d181ea5a70f08a55a Mon Sep 17 00:00:00 2001 From: "Greg T. Wallace" Date: Fri, 19 Jan 2024 17:26:14 -0500 Subject: [PATCH] initial commit: header * func to write the header APC NMC expects --- .gitignore | 3 ++ file_header.go | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 5 ++++ go.sum | 2 ++ main.go | 37 +++++++++++++++++++++++++ 5 files changed, 121 insertions(+) create mode 100644 .gitignore create mode 100644 file_header.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 main.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2781dd2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# key/cert files +*.p15 +*.pem diff --git a/file_header.go b/file_header.go new file mode 100644 index 0000000..eef3550 --- /dev/null +++ b/file_header.go @@ -0,0 +1,74 @@ +package main + +import ( + "encoding/binary" + "errors" + + "github.com/sigurn/crc16" +) + +// makeFileHeader generates the 228 byte header to prepend to the .p15 +// as required by APC UPS NMC. Only 2,048 bit RSA keys are supported +// so the header will always be written with that key size assumption +func makeFileHeader(p15File []byte) ([]byte, error) { + // original reference code from: https://github.com/bbczeuz/apc_tools + // // add APC header + // *(uint32_t *)(buf + 0) = 1; // always 1 + // *(uint32_t *)(buf + 4) = 1; // always 1 + // strncpy((char *)(buf + 8), "SecurityWizard103", 0xC8); // apparently supposed to identify the creating tool, SecWiz v1.04 sill puts 103 here + // *(uint32_t *)(buf + 208) = 1; // always 1 + // *(uint32_t *)(buf + 212) = 1; // always 1 + // *(uint32_t *)(buf + 216) = fileSize; // size of the following data + // *(uint32_t *)(buf + 208) = keySize; // 1 for 1024 key, otherwise (2048 bit) 2 + // // 16 bit checksums are moved to 32 bit int with sign-extension + // *(uint32_t *)(buf + 220) = (int32_t)calc_cksum(0, buf + 228, fileSize); // checksum of the original file + // *(uint32_t *)(buf + 224) = (int32_t)calc_cksum(0, buf, 224); // checksum of the APC header + + // NOTE: This line is unused as it seems the APC tool code always writes this as a 1 for 2,048 bit + // *(uint32_t *)(buf + 208) = keySize; // 1 for 1024 key, otherwise (2048 bit) 2 + // Unsure why this was in original code but seems irrelevant + + header := make([]byte, 228) + + // always 1 + header[0] = 1 + + // always 1 + header[4] = 1 + + // apparently supposed to identify the creating tool + toolName := "NMCSecurityWizardCLI100" + toolNameBytes := []byte(toolName) + if len(toolNameBytes) > 200 { + return nil, errors.New("tool name is too big to fit in header") + } + copy(header[8:], toolNameBytes) + + // always 1 + header[208] = 1 + + // always 1 + header[212] = 1 + + // size of the data after the header (the actual p15 file) + size := make([]byte, 4) + binary.LittleEndian.PutUint32(size, uint32(len(p15File))) + copy(header[216:], size) + + // check sums (CRC Table) + checksumTable := crc16.MakeTable(crc16.CRC16_XMODEM) + + // file checksum + fileChecksum := make([]byte, 4) + binary.LittleEndian.PutUint16(fileChecksum, crc16.Checksum(p15File, checksumTable)) + copy(header[220:], fileChecksum) + + // header checksum + headerChecksum := make([]byte, 4) + binary.LittleEndian.PutUint16(headerChecksum, crc16.Checksum(header[:224], checksumTable)) + copy(header[224:], headerChecksum) + + // this was in original code but + + return header, nil +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..cdd2295 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module temp + +go 1.21 + +require github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a505f78 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3 h1:aQKxg3+2p+IFXXg97McgDGT5zcMrQoi0EICZs8Pgchs= +github.com/sigurn/crc16 v0.0.0-20211026045750-20ab5afb07e3/go.mod h1:9/etS5gpQq9BJsJMWg1wpLbfuSnkm8dPF6FdW2JXVhA= diff --git a/main.go b/main.go new file mode 100644 index 0000000..21f0009 --- /dev/null +++ b/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "log" + "os" +) + +func main() { + p15Bytes, err := os.ReadFile("./apc9138a8cert-no-header.p15") + if err != nil { + panic(err) + } + + apcHeader, err := makeFileHeader(p15Bytes) + if err != nil { + panic(err) + } + + wizardBytes, err := os.ReadFile("./apc9138a.apc-wizard.p15") + if err != nil { + panic(err) + } + + wizHeader := wizardBytes[:228] + + log.Println(apcHeader) + log.Println(wizHeader) + + for i := range wizHeader { + if apcHeader[i] != wizHeader[i] { + panic(i) + } + } + + log.Println("match") + +}