Files
cheese/tesseract/genconf/key_test.go
2025-08-28 21:15:13 +02:00

296 lines
6.8 KiB
Go

package main
import (
"crypto/elliptic"
"crypto/x509"
"encoding/pem"
"os"
"path/filepath"
"strings"
"testing"
)
func TestGenerateKeys(t *testing.T) {
tmpDir := t.TempDir()
// Create test directories
keyDir := filepath.Join(tmpDir, "keys")
err := os.MkdirAll(keyDir, 0755)
if err != nil {
t.Fatal(err)
}
// Create test config
key1Path := filepath.Join(keyDir, "test-log-1.key")
key2Path := filepath.Join(keyDir, "test-log-2.key")
configContent := `logs:
- shortname: "test-log-1"
secret: "` + key1Path + `"
- shortname: "test-log-2"
secret: "` + key2Path + `"`
configFile := filepath.Join(tmpDir, "test-config.yaml")
err = os.WriteFile(configFile, []byte(configContent), 0644)
if err != nil {
t.Fatal(err)
}
// Run generateKeys
generateKeys(configFile, false, true, false)
// Verify first key was created
if _, err := os.Stat(key1Path); os.IsNotExist(err) {
t.Error("Expected first key file to be created")
}
// Verify second key was created
if _, err := os.Stat(key2Path); os.IsNotExist(err) {
t.Error("Expected second key file to be created")
}
// Verify key format
keyContent, err := os.ReadFile(key1Path)
if err != nil {
t.Fatal(err)
}
keyStr := string(keyContent)
if !strings.Contains(keyStr, "-----BEGIN EC PRIVATE KEY-----") {
t.Error("Expected EC private key PEM header")
}
if !strings.Contains(keyStr, "-----END EC PRIVATE KEY-----") {
t.Error("Expected EC private key PEM footer")
}
// Verify key can be parsed
block, _ := pem.Decode(keyContent)
if block == nil {
t.Error("Failed to decode PEM block")
}
privKey, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
t.Errorf("Failed to parse EC private key: %v", err)
}
// Verify it's a P-256 key
if privKey.Curve != elliptic.P256() {
t.Error("Expected P-256 curve")
}
// Verify file permissions
info, err := os.Stat(key1Path)
if err != nil {
t.Fatal(err)
}
perm := info.Mode().Perm()
expected := os.FileMode(0600)
if perm != expected {
t.Errorf("Expected file mode %o, got %o", expected, perm)
}
}
func TestGenerateKeysExistingKey(t *testing.T) {
tmpDir := t.TempDir()
// Create existing key file
keyPath := filepath.Join(tmpDir, "existing.key")
existingContent := `-----BEGIN EC PRIVATE KEY-----
MHcCAQEEIExistingKeyContent
-----END EC PRIVATE KEY-----`
err := os.WriteFile(keyPath, []byte(existingContent), 0600)
if err != nil {
t.Fatal(err)
}
// Create test config
configContent := `logs:
- shortname: "test-log"
secret: "` + keyPath + `"`
configFile := filepath.Join(tmpDir, "test-config.yaml")
err = os.WriteFile(configFile, []byte(configContent), 0644)
if err != nil {
t.Fatal(err)
}
// Run generateKeys
generateKeys(configFile, false, true, false)
// Verify existing key was not overwritten
keyContent, err := os.ReadFile(keyPath)
if err != nil {
t.Fatal(err)
}
if string(keyContent) != existingContent {
t.Error("Expected existing key to be preserved")
}
}
func TestGenerateKeysWithoutWriteFlag(t *testing.T) {
tmpDir := t.TempDir()
keyPath := filepath.Join(tmpDir, "test.key")
configContent := `logs:
- shortname: "test-log"
secret: "` + keyPath + `"`
configFile := filepath.Join(tmpDir, "test-config.yaml")
err := os.WriteFile(configFile, []byte(configContent), 0644)
if err != nil {
t.Fatal(err)
}
// Run generateKeys without write flag
generateKeys(configFile, false, false, false)
// Verify key was not created
if _, err := os.Stat(keyPath); !os.IsNotExist(err) {
t.Error("Expected key file to not be created without --write flag")
}
}
func TestGenerateKeysCreateDirectory(t *testing.T) {
tmpDir := t.TempDir()
// Key path with non-existent directory
keyDir := filepath.Join(tmpDir, "subdir", "keys")
keyPath := filepath.Join(keyDir, "test.key")
configContent := `logs:
- shortname: "test-log"
secret: "` + keyPath + `"`
configFile := filepath.Join(tmpDir, "test-config.yaml")
err := os.WriteFile(configFile, []byte(configContent), 0644)
if err != nil {
t.Fatal(err)
}
// Run generateKeys
generateKeys(configFile, false, true, false)
// Verify directory was created
if _, err := os.Stat(keyDir); os.IsNotExist(err) {
t.Error("Expected directory to be created")
}
// Verify key was created
if _, err := os.Stat(keyPath); os.IsNotExist(err) {
t.Error("Expected key file to be created")
}
}
func TestGenerateKeysMultipleRuns(t *testing.T) {
tmpDir := t.TempDir()
key1Path := filepath.Join(tmpDir, "key1.key")
key2Path := filepath.Join(tmpDir, "key2.key")
configContent := `logs:
- shortname: "test-log-1"
secret: "` + key1Path + `"
- shortname: "test-log-2"
secret: "` + key2Path + `"`
configFile := filepath.Join(tmpDir, "test-config.yaml")
err := os.WriteFile(configFile, []byte(configContent), 0644)
if err != nil {
t.Fatal(err)
}
// First run - should create both keys
generateKeys(configFile, false, true, false)
// Read first key content
key1Content, err := os.ReadFile(key1Path)
if err != nil {
t.Fatal(err)
}
key2Content, err := os.ReadFile(key2Path)
if err != nil {
t.Fatal(err)
}
// Second run - should not overwrite existing keys
generateKeys(configFile, false, true, false)
// Verify keys are unchanged
key1Content2, err := os.ReadFile(key1Path)
if err != nil {
t.Fatal(err)
}
key2Content2, err := os.ReadFile(key2Path)
if err != nil {
t.Fatal(err)
}
if string(key1Content) != string(key1Content2) {
t.Error("First key should not have been overwritten")
}
if string(key2Content) != string(key2Content2) {
t.Error("Second key should not have been overwritten")
}
}
func TestECKeyGeneration(t *testing.T) {
tmpDir := t.TempDir()
keyPath := filepath.Join(tmpDir, "test.key")
configContent := `logs:
- shortname: "test-log"
secret: "` + keyPath + `"`
configFile := filepath.Join(tmpDir, "test-config.yaml")
err := os.WriteFile(configFile, []byte(configContent), 0644)
if err != nil {
t.Fatal(err)
}
generateKeys(configFile, false, true, false)
// Read and parse the generated key
keyContent, err := os.ReadFile(keyPath)
if err != nil {
t.Fatal(err)
}
block, _ := pem.Decode(keyContent)
if block == nil {
t.Fatal("Failed to decode PEM block")
}
if block.Type != "EC PRIVATE KEY" {
t.Errorf("Expected block type 'EC PRIVATE KEY', got %s", block.Type)
}
privKey, err := x509.ParseECPrivateKey(block.Bytes)
if err != nil {
t.Fatalf("Failed to parse EC private key: %v", err)
}
// Verify public key can be derived
pubKey := &privKey.PublicKey
if pubKey.X == nil || pubKey.Y == nil {
t.Error("Public key coordinates should not be nil")
}
// Verify key is on the correct curve
if !pubKey.Curve.IsOnCurve(pubKey.X, pubKey.Y) {
t.Error("Public key is not on the curve")
}
// Verify we can marshal the public key (for log ID computation)
_, err = x509.MarshalPKIXPublicKey(pubKey)
if err != nil {
t.Errorf("Failed to marshal public key: %v", err)
}
}