Pull request 2459: AG-45496-fix-tls-warning

Squashed commit of the following:

commit 9b634e388c
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Aug 27 20:20:43 2025 +0300

    home: add tests

commit ab84e3be17
Author: Stanislav Chzhen <s.chzhen@adguard.com>
Date:   Wed Aug 27 13:42:25 2025 +0300

    all: fix tls warning
This commit is contained in:
Stanislav Chzhen
2025-08-28 19:03:13 +03:00
parent 613a4b97b9
commit 52398e27ec
3 changed files with 96 additions and 3 deletions

View File

@@ -17,6 +17,11 @@ See also the [v0.107.66 GitHub milestone][ms-v0.107.66].
NOTE: Add new changes BELOW THIS COMMENT.
-->
### Fixed
- Missing warning on the *Encryption Settings* page when using a certificate without an IP address.
<!--
NOTE: Add new changes ABOVE THIS COMMENT.
-->

View File

@@ -907,11 +907,13 @@ func (m *tlsManager) validateCertificate(
certChain []byte,
serverName string,
) (ok bool, err error) {
// parseErr is a non-critical parse warning.
var parseErr error
var certs []*x509.Certificate
certs, status.ValidCert, err = m.parseCertChain(ctx, certChain)
certs, status.ValidCert, parseErr = m.parseCertChain(ctx, certChain)
if !status.ValidCert {
// Don't wrap the error, since it's informative enough as is.
return false, err
return false, parseErr
}
mainCert := certs[0]
@@ -930,7 +932,8 @@ func (m *tlsManager) validateCertificate(
status.ValidChain = true
return true, nil
// Propagate the non-critical parse warning.
return true, parseErr
}
// Key types.

View File

@@ -106,6 +106,29 @@ func TestValidateCertificates(t *testing.T) {
assert.Equal(t, notAfter, status.NotAfter)
assert.True(t, status.ValidPair)
})
t.Run("no_ip_in_cert", func(t *testing.T) {
caCert, chainPEM, leafKeyPEM := newCertWithoutIP(t)
m.rootCerts = x509.NewCertPool()
m.rootCerts.AddCert(caCert)
status := &tlsConfigStatus{}
var ok bool
ok, err = m.validateCertificate(ctx, status, chainPEM, "")
assert.True(t, ok)
assert.ErrorIs(t, err, errNoIPInCert)
assert.True(t, status.ValidCert)
assert.True(t, status.ValidChain)
status = &tlsConfigStatus{}
err = m.validateCertificates(ctx, status, chainPEM, leafKeyPEM, "")
assert.ErrorIs(t, err, errNoIPInCert)
assert.True(t, status.ValidCert)
assert.True(t, status.ValidChain)
assert.True(t, status.ValidKey)
assert.True(t, status.ValidPair)
})
}
// storeGlobals is a test helper function that saves global variables and
@@ -145,6 +168,68 @@ func storeGlobals(tb testing.TB) {
})
}
// newCertWithoutIP generates a CA certificate, a leaf certificate without an IP
// address, and the PEM-encoded leaf private key.
func newCertWithoutIP(tb testing.TB) (
caCert *x509.Certificate,
chainPEM []byte,
leafKeyPEM []byte,
) {
tb.Helper()
caKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(tb, err)
now := time.Now()
caTmpl := &x509.Certificate{
SerialNumber: big.NewInt(1),
NotBefore: now.Add(-time.Hour),
NotAfter: now.Add(time.Hour),
IsCA: true,
BasicConstraintsValid: true,
KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign,
}
caDER, err := x509.CreateCertificate(rand.Reader, caTmpl, caTmpl, &caKey.PublicKey, caKey)
require.NoError(tb, err)
caCert, err = x509.ParseCertificate(caDER)
require.NoError(tb, err)
leafKey, err := rsa.GenerateKey(rand.Reader, 2048)
require.NoError(tb, err)
leafTmpl := &x509.Certificate{
SerialNumber: big.NewInt(2),
NotBefore: now.Add(-time.Hour),
NotAfter: now.Add(time.Hour),
KeyUsage: x509.KeyUsageDigitalSignature,
}
leafDER, err := x509.CreateCertificate(
rand.Reader,
leafTmpl,
caTmpl,
&leafKey.PublicKey,
caKey,
)
require.NoError(tb, err)
buf := bytes.Buffer{}
err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: leafDER})
require.NoError(tb, err)
err = pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: caDER})
require.NoError(tb, err)
leafKeyPEM = pem.EncodeToMemory(&pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: x509.MarshalPKCS1PrivateKey(leafKey),
})
return caCert, buf.Bytes(), leafKeyPEM
}
// newCertAndKey is a helper function that generates certificate and key.
func newCertAndKey(tb testing.TB, n int64) (certDER []byte, key *rsa.PrivateKey) {
tb.Helper()