From 83df31ec800d25fd49cbb8a931e3b4d3e081f561 Mon Sep 17 00:00:00 2001 From: Abel Luck Date: Wed, 10 Sep 2025 13:01:01 +0200 Subject: [PATCH] Fix incorrect RSA identity key fingerprint generation The fingerprint calculation was using PKIX encoding instead of the required PKCS1 DER encoding for RSA public keys. This affected both the relay identity resource and obfs4 node ID derivation. - Use x509.MarshalPKCS1PublicKey instead of x509.MarshalPKIXPublicKey - Add test case with known fingerprint vector to prevent regression - Update both generateFingerprints and deriveNodeIdFromRsaKey functions fixes #2 --- .../tor_obfs4_bridge_line_data_source_test.go | 1 - internal/provider/tor_obfs4_state_resource.go | 6 +-- ...or_relay_identity_ed25519_resource_test.go | 1 - .../tor_relay_identity_rsa_resource.go | 5 +-- .../tor_relay_identity_rsa_resource_test.go | 44 ++++++++++++++++++- 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/internal/provider/tor_obfs4_bridge_line_data_source_test.go b/internal/provider/tor_obfs4_bridge_line_data_source_test.go index d600fe0..d4032a2 100644 --- a/internal/provider/tor_obfs4_bridge_line_data_source_test.go +++ b/internal/provider/tor_obfs4_bridge_line_data_source_test.go @@ -31,7 +31,6 @@ func TestTorObfs4BridgeLineDataSource(t *testing.T) { // Check computed values are generated resource.TestCheckResourceAttrSet("data.tor_obfs4_bridge_line.test", "bridge_line"), - // Check bridge line format resource.TestMatchResourceAttr("data.tor_obfs4_bridge_line.test", "bridge_line", regexp.MustCompile(`^Bridge obfs4 192\.0\.2\.1:443 [0-9a-f]{40} cert=[A-Za-z0-9+/]+ iat-mode=[0-2]$`)), diff --git a/internal/provider/tor_obfs4_state_resource.go b/internal/provider/tor_obfs4_state_resource.go index 97e8dd5..7fe87b3 100644 --- a/internal/provider/tor_obfs4_state_resource.go +++ b/internal/provider/tor_obfs4_state_resource.go @@ -406,11 +406,7 @@ func (r *TorObfs4StateResource) deriveNodeIdFromRsaKey(rsaPrivateKeyPem string) return nil, fmt.Errorf("failed to parse RSA private key: %w", err) } - // Extract the public key and encode it - publicKeyBytes, err := x509.MarshalPKIXPublicKey(&privateKey.PublicKey) - if err != nil { - return nil, fmt.Errorf("failed to marshal public key: %w", err) - } + publicKeyBytes := x509.MarshalPKCS1PublicKey(&privateKey.PublicKey) // Generate SHA1 hash of public key (this is the relay fingerprint/node ID) hash := sha1.Sum(publicKeyBytes) diff --git a/internal/provider/tor_relay_identity_ed25519_resource_test.go b/internal/provider/tor_relay_identity_ed25519_resource_test.go index 7b0873e..50396ea 100644 --- a/internal/provider/tor_relay_identity_ed25519_resource_test.go +++ b/internal/provider/tor_relay_identity_ed25519_resource_test.go @@ -27,7 +27,6 @@ func TestAccTorRelayIdentityEd25519Resource(t *testing.T) { // Verify PEM format resource.TestMatchResourceAttr("tor_relay_identity_ed25519.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN PRIVATE KEY-----`)), resource.TestMatchResourceAttr("tor_relay_identity_ed25519.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY-----`)), - // Verify fingerprint format (64 hex characters for SHA256) resource.TestMatchResourceAttr("tor_relay_identity_ed25519.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^[0-9a-f]{64}$`)), ), }, diff --git a/internal/provider/tor_relay_identity_rsa_resource.go b/internal/provider/tor_relay_identity_rsa_resource.go index 2a6e453..f7f5e00 100644 --- a/internal/provider/tor_relay_identity_rsa_resource.go +++ b/internal/provider/tor_relay_identity_rsa_resource.go @@ -196,10 +196,7 @@ func (r *TorRelayIdentityRsaResource) encodePublicKeyPEM(publicKey *rsa.PublicKe } func (r *TorRelayIdentityRsaResource) generateFingerprints(publicKey *rsa.PublicKey) (string, string, error) { - publicKeyBytes, err := x509.MarshalPKIXPublicKey(publicKey) - if err != nil { - return "", "", err - } + publicKeyBytes := x509.MarshalPKCS1PublicKey(publicKey) sha1Sum := sha1.Sum(publicKeyBytes) sha256Sum := sha256.Sum256(publicKeyBytes) diff --git a/internal/provider/tor_relay_identity_rsa_resource_test.go b/internal/provider/tor_relay_identity_rsa_resource_test.go index f670f89..a3df3cd 100644 --- a/internal/provider/tor_relay_identity_rsa_resource_test.go +++ b/internal/provider/tor_relay_identity_rsa_resource_test.go @@ -4,6 +4,8 @@ package provider import ( + "crypto/x509" + "encoding/pem" "regexp" "testing" @@ -28,7 +30,6 @@ func TestAccTorRelayIdentityRsaResource(t *testing.T) { // Verify PEM format resource.TestMatchResourceAttr("tor_relay_identity_rsa.test", "private_key_pem", regexp.MustCompile(`^-----BEGIN RSA PRIVATE KEY-----`)), resource.TestMatchResourceAttr("tor_relay_identity_rsa.test", "public_key_pem", regexp.MustCompile(`^-----BEGIN PUBLIC KEY-----`)), - // Verify fingerprint formats (hex strings) resource.TestMatchResourceAttr("tor_relay_identity_rsa.test", "public_key_fingerprint_sha1", regexp.MustCompile(`^[0-9a-f]{40}$`)), resource.TestMatchResourceAttr("tor_relay_identity_rsa.test", "public_key_fingerprint_sha256", regexp.MustCompile(`^[0-9a-f]{64}$`)), ), @@ -37,6 +38,47 @@ func TestAccTorRelayIdentityRsaResource(t *testing.T) { }) } +func TestRsaFingerprintGeneration(t *testing.T) { + testRsaPrivateKeyPem := `-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDxZrR1gsB00rE5Rift0y35j/F5Jt03ExlW0H7fUI+4W2MyZ+pE +0CM512o1tshfpDVxtVrnJuI8dFAVgO9Ct7aEKYTNk++g9llF+Q0M4nIrKftv/4Fo +MlFHwa+C41LGiucauaagiatiESNWNK3FhOLx1Who9duUN5SVVFyXpApPrQIDAQAB +AoGAJya2G9zh49CMB7L2JN88NJ6A1lpURGtnj6nu+b7yID9KHlG2MATlwarLQfzs +EH7sYA2+uYCX7qAaoPIxW8u54PLKbgVD3Kh7eXBO0isIx4FPMHD4khv5CLiNVopI +VwStg9Fv3FZ6h2+2FTVfLK4+xuwfyoShUwfEp3eV7c8YRSECQQD1ntdJrokM2zWR +hf+Cl/L62tl58hSYVZoSrR+b0cTQlbN1rnYTvY+1jXbBP8fKFBoAHKZ1xMCY/m67 +H7qt+nalAkEA+5o4GQb6YCHYJZ/lhGQFaSGnWnKE16MsW1xLimQY8gOMbg3AYcXk +B8fylmp/XpNG1/PC+M6m5C0DjI85eKYuaQJBAJ2eOPmHj1s4sL+aBcWATOS93CFt +P9oh1KV3g3kyu+I+rtMuCYfRdY9EIJkSnNsI20aHHCsm/5EudVCPo/RRbiECQEQu +psUhfvhOM6T+j9QwxsaWuCNqpVVKgtq/SDlYpunuzD+GunvEhOcW6Eaa1alrf+dF +x7BlUBTFnhCZP5nSbwECQGgUr7jW/xrwbkDAP3+ql6o0yyhLMtvIqAKk3fUWxPXO +OhEqFiIYW5mI//JWsqSZZxy4nMqgejKkrRgOOQbL0NE= +-----END RSA PRIVATE KEY-----` + + expectedSha1Fingerprint := "da5cec632a9a544394403bd533e1a7bde2f26edd" + + block, _ := pem.Decode([]byte(testRsaPrivateKeyPem)) + if block == nil { + t.Fatal("failed to decode PEM block") + } + + privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes) + if err != nil { + t.Fatalf("failed to parse RSA private key: %v", err) + } + + resource := &TorRelayIdentityRsaResource{} + sha1Fingerprint, _, err := resource.generateFingerprints(&privateKey.PublicKey) + if err != nil { + t.Fatalf("failed to generate fingerprint: %v", err) + } + + if sha1Fingerprint != expectedSha1Fingerprint { + t.Errorf("SHA1 fingerprint mismatch:\nExpected: %s\nActual: %s", + expectedSha1Fingerprint, sha1Fingerprint) + } +} + const testAccTorRelayIdentityRsaResourceConfig = ` resource "tor_relay_identity_rsa" "test" {} `