Sfoglia il codice sorgente

Refuse print-cert for a tunnel that has no certificate yet

print-cert dereferenced the tunnel's certificate without checking it, so
naming a tunnel still handshaking, or one being torn down, panicked; ssh
has no recover. The bug is inherited from master. The identity lookup
already guarded the same case.

- a tunnel without a certificate is answered as one that is not there
- test with the identity fixture's handshaking tunnel

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Matt Richardson 1 giorno fa
parent
commit
a36f0dc4d6
2 ha cambiato i file con 21 aggiunte e 1 eliminazioni
  1. 6 1
      commands.go
  2. 15 0
      commands_test.go

+ 6 - 1
commands.go

@@ -521,7 +521,12 @@ func runPrintCert(ifce *Interface, args *printCertFlags, a []string) (commands.R
 		if !ok {
 			return res, nil
 		}
-		c = hostInfo.GetCert().Certificate
+		// A tunnel still handshaking, or one being torn down, has no certificate.
+		cc := hostInfo.GetCert()
+		if cc == nil {
+			return commands.Failed("Could not find tunnel for vpn addr: %v", a[0]), nil
+		}
+		c = cc.Certificate
 	}
 
 	if args.Raw {

+ 15 - 0
commands_test.go

@@ -65,3 +65,18 @@ func TestPrintRelaysReportsErrorsAsText(t *testing.T) {
 	delete(hm.Relays, 1)
 	assert.Contains(t, marshal(), `"Error":"hostmap LocalIndex '7' does not match RelayState LocalIndex"`)
 }
+
+// TestPrintCertOfATunnelWithoutACertificate: a tunnel still handshaking, or one being
+// torn down, has no certificate, and print-cert refuses rather than panicking.
+func TestPrintCertOfATunnelWithoutACertificate(t *testing.T) {
+	f, _ := identityFixture(t)
+
+	r, err := runPrintCert(f, &printCertFlags{}, []string{"10.0.0.3"})
+	require.NoError(t, err)
+	assert.False(t, r.OK)
+	assert.Equal(t, "Could not find tunnel for vpn addr: 10.0.0.3", r.Reason)
+
+	r, err = runPrintCert(f, &printCertFlags{}, []string{"10.0.0.2"})
+	require.NoError(t, err)
+	assert.True(t, r.OK, "a tunnel with a certificate is printed")
+}