chore: establish local platform baseline
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
type signedFirmware struct {
|
||||
PublicKeyBase64 string `json:"public_key_base64"`
|
||||
SignatureBase64 string `json:"signature_base64"`
|
||||
SHA256 string `json:"sha256"`
|
||||
Size int `json:"size"`
|
||||
Manifest string `json:"manifest"`
|
||||
}
|
||||
|
||||
func main() {
|
||||
if len(os.Args) != 5 {
|
||||
fmt.Fprintln(os.Stderr, "usage: firmware-sign <model> <hardware-revision> <version> <file>")
|
||||
os.Exit(2)
|
||||
}
|
||||
content, err := os.ReadFile(os.Args[4])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
result, err := signFirmware(os.Args[1], os.Args[2], os.Args[3], content)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
if err := json.NewEncoder(os.Stdout).Encode(result); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func signFirmware(model, hardwareRevision, version string, content []byte) (signedFirmware, error) {
|
||||
publicKey, privateKey, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
return signedFirmware{}, err
|
||||
}
|
||||
digest := sha256.Sum256(content)
|
||||
digestText := hex.EncodeToString(digest[:])
|
||||
manifest := fmt.Sprintf("firmware-manifest-v1\nmodel=%s\nhardware_revision=%s\nversion=%s\nsha256=%s\nsize=%d\n", model, hardwareRevision, version, digestText, len(content))
|
||||
return signedFirmware{
|
||||
PublicKeyBase64: base64.StdEncoding.EncodeToString(publicKey),
|
||||
SignatureBase64: base64.StdEncoding.EncodeToString(ed25519.Sign(privateKey, []byte(manifest))),
|
||||
SHA256: digestText, Size: len(content), Manifest: manifest,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/ed25519"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSignFirmwareProducesVerifiableManifest(t *testing.T) {
|
||||
content := []byte("deterministic firmware fixture")
|
||||
result, err := signFirmware("terminal-a", "rev-b", "1.2.3", content)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
digest := sha256.Sum256(content)
|
||||
if result.SHA256 != hex.EncodeToString(digest[:]) || result.Size != len(content) {
|
||||
t.Fatalf("digest=%s size=%d", result.SHA256, result.Size)
|
||||
}
|
||||
for _, fragment := range []string{"model=terminal-a", "hardware_revision=rev-b", "version=1.2.3", "sha256=" + result.SHA256} {
|
||||
if !strings.Contains(result.Manifest, fragment) {
|
||||
t.Fatalf("manifest missing %q: %s", fragment, result.Manifest)
|
||||
}
|
||||
}
|
||||
publicKey, err := base64.StdEncoding.DecodeString(result.PublicKeyBase64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
signature, err := base64.StdEncoding.DecodeString(result.SignatureBase64)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !ed25519.Verify(ed25519.PublicKey(publicKey), []byte(result.Manifest), signature) {
|
||||
t.Fatal("firmware signature did not verify")
|
||||
}
|
||||
if ed25519.Verify(ed25519.PublicKey(publicKey), []byte(result.Manifest+"tampered"), signature) {
|
||||
t.Fatal("tampered manifest unexpectedly verified")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user