Skip to content

Commit

Permalink
ca: support IP address as SAN
Browse files Browse the repository at this point in the history
  • Loading branch information
burgerdev committed Mar 20, 2024
1 parent 27ab5d1 commit c0f47a9
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 14 deletions.
16 changes: 15 additions & 1 deletion internal/ca/ca.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"encoding/pem"
"errors"
"fmt"
"net"
"sync"
"time"

Expand Down Expand Up @@ -72,7 +73,19 @@ func New() (*CA, error) {
}

// NewAttestedMeshCert creates a new attested mesh certificate.
func (c *CA) NewAttestedMeshCert(dnsNames []string, extensions []pkix.Extension, subjectPublicKey any) ([]byte, error) {
func (c *CA) NewAttestedMeshCert(names []string, extensions []pkix.Extension, subjectPublicKey any) ([]byte, error) {
var dnsNames []string
var ips []net.IP
for _, name := range names {
// If a string parses correctly as an IP address, it is not a valid DNS name anyway, so we
// can split the SANs into DNS and IP by that predicate.
if ip := net.ParseIP(name); ip != nil {
ips = append(ips, ip)
} else {
dnsNames = append(dnsNames, name)
}
}

c.intermMux.RLock()
defer c.intermMux.RUnlock()
now := time.Now()
Expand All @@ -86,6 +99,7 @@ func (c *CA) NewAttestedMeshCert(dnsNames []string, extensions []pkix.Extension,
BasicConstraintsValid: true,
ExtraExtensions: extensions,
DNSNames: dnsNames,
IPAddresses: ips,
}

certPEM, err := createCert(certTemplate, c.meshCACert, subjectPublicKey, c.intermPrivKey)
Expand Down
32 changes: 19 additions & 13 deletions internal/ca/ca_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ func TestNewCA(t *testing.T) {
ok := root.AppendCertsFromPEM(ca.rootPEM)
assert.True(ok)

block, _ := pem.Decode(ca.intermPEM)
require.NotNil(block)
cert, err := x509.ParseCertificate(block.Bytes)
require.NoError(err)
cert := parsePEMCertificate(t, ca.intermPEM)

opts := x509.VerifyOptions{Roots: root}

Expand All @@ -52,12 +49,19 @@ func TestAttestedMeshCert(t *testing.T) {
extensions []pkix.Extension
subjectPub any
wantErr bool
wantIPs int
}{
"valid": {
dnsNames: []string{"foo", "bar"},
extensions: []pkix.Extension{},
subjectPub: newKey(req).Public(),
},
"ips": {
dnsNames: []string{"foo", "192.0.2.1"},
extensions: []pkix.Extension{},
subjectPub: newKey(req).Public(),
wantIPs: 1,
},
}

for name, tc := range testCases {
Expand All @@ -68,20 +72,21 @@ func TestAttestedMeshCert(t *testing.T) {
ca, err := New()
require.NoError(err)

cert, err := ca.NewAttestedMeshCert(tc.dnsNames, tc.extensions, tc.subjectPub)
pem, err := ca.NewAttestedMeshCert(tc.dnsNames, tc.extensions, tc.subjectPub)
if tc.wantErr {
assert.Error(err)
return
}
assert.NoError(err)
assert.NotNil(cert)
assert.NotNil(pem)

assertValidPEM(assert, cert)
cert := parsePEMCertificate(t, pem)
assert.Len(cert.IPAddresses, tc.wantIPs)
})
}
}

func TestCerateCert(t *testing.T) {
func TestCreateCert(t *testing.T) {
req := require.New(t)

testCases := map[string]struct {
Expand Down Expand Up @@ -141,7 +146,7 @@ func TestCerateCert(t *testing.T) {
}

assert.NoError(err)
assertValidPEM(assert, pem)
parsePEMCertificate(t, pem)
})
}
}
Expand Down Expand Up @@ -236,9 +241,10 @@ func newKey(require *require.Assertions) *ecdsa.PrivateKey {
return key
}

func assertValidPEM(assert *assert.Assertions, data []byte) {
func parsePEMCertificate(t *testing.T, data []byte) *x509.Certificate {
block, _ := pem.Decode(data)
assert.NotNil(block)
_, err := x509.ParseCertificate(block.Bytes)
assert.NoError(err)
require.NotNil(t, block)
cert, err := x509.ParseCertificate(block.Bytes)
require.NoError(t, err)
return cert
}

0 comments on commit c0f47a9

Please sign in to comment.