Skip to content

Commit c83f08e

Browse files
committed
Use pkutil for loading private key
Signed-off-by: Aswin Suryanarayanan <asuryan@redhat.com> Signed-off-by: Tom Pantelis <tompantelis@gmail.com>
1 parent fa47a74 commit c83f08e

File tree

4 files changed

+74
-44
lines changed

4 files changed

+74
-44
lines changed

pkg/cable/libreswan/certificate_auth_mode.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ import (
3030

3131
func (i *libreswan) connectToEndpointCertMode(endpointInfo *natdiscovery.NATEndpointInfo) (string, error) {
3232
endpoint := &endpointInfo.Endpoint
33-
leftID := "submariner-client-" + i.localEndpoint.ClusterID
33+
leftID := ClientCertName
3434
left := i.localEndpoint.GetPrivateIP(endpointInfo.UseFamily)
3535
right := endpointInfo.UseIP
3636

pkg/cable/libreswan/certificate_handler.go

Lines changed: 66 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -39,20 +39,17 @@ var certLogger = log.Logger{Logger: logf.Log.WithName("CertHandler")}
3939
const (
4040
CACertName = "subm-ca-cert"
4141
ClientCertName = "subm-client-cert"
42-
ClientKeyName = "subm-client-key"
4342
)
4443

4544
// CertificateHandler handles NSS database operations for certificates.
4645
type CertificateHandler struct {
47-
clusterID string
4846
nssDBDir string
4947
lastCertHash string
5048
}
5149

52-
func NewCertificateHandler(clusterID string) *CertificateHandler {
50+
func NewCertificateHandler() *CertificateHandler {
5351
return &CertificateHandler{
54-
clusterID: clusterID,
55-
nssDBDir: RootDir + "/var/lib/ipsec/nss",
52+
nssDBDir: RootDir + "/var/lib/ipsec/nss",
5653
}
5754
}
5855

@@ -64,7 +61,7 @@ func (c *CertificateHandler) initNSSDatabase(ctx context.Context) error {
6461

6562
certLogger.Info("NSS database does not exist, initializing new database")
6663

67-
if err := execCertUtil(command.New(c.newCertUtilCmd(ctx, "-N", "--empty-password"))); err != nil {
64+
if err := execWithOutput(command.New(c.newCertUtilCmd(ctx, "-N", "--empty-password"))); err != nil {
6865
return errors.Wrap(err, "failed to initialize NSS database")
6966
}
7067

@@ -75,45 +72,79 @@ func (c *CertificateHandler) initNSSDatabase(ctx context.Context) error {
7572

7673
func (c *CertificateHandler) loadCertificatesIntoNSS(ctx context.Context, tlsCert, tlsKey, caCert []byte) error {
7774
// Load CA certificate
78-
if err := c.loadCertificate(ctx, caCert, CACertName, "C,,"); err != nil {
75+
if err := c.loadCertificate(ctx, caCert, CACertName, "CT,"); err != nil {
7976
return errors.Wrap(err, "failed to load CA certificate")
8077
}
8178

82-
// Load client certificate
83-
if err := c.loadCertificate(ctx, tlsCert, ClientCertName, "C,,"); err != nil {
84-
return errors.Wrap(err, "failed to load client certificate")
85-
}
86-
87-
// Load client private key
88-
err := c.loadPrivateKey(ctx, tlsKey, ClientKeyName)
79+
// Load client certificate and key using pk12util
80+
err := c.loadPrivateKey(ctx, tlsCert, tlsKey, ClientCertName)
8981

90-
return errors.Wrap(err, "failed to load client private key")
82+
return errors.Wrap(err, "failed to load client certificate with key")
9183
}
9284

9385
func (c *CertificateHandler) loadCertificate(ctx context.Context, certData []byte, nickname, trustFlags string) error {
94-
execCmd := c.newCertUtilCmd(ctx, "-A", "-n", nickname, "-t", trustFlags, "-i", "-", "-a")
86+
execCmd := c.newCertUtilCmd(ctx, "-A", "-n", nickname, "-t", trustFlags, "-a")
9587
execCmd.Stdin = bytes.NewReader(certData)
9688

97-
cmd := command.New(execCmd)
89+
err := execWithOutput(command.New(execCmd))
9890

99-
if err := execCertUtil(cmd); err != nil {
100-
return errors.Wrapf(err, "failed to load certificate %q", nickname)
91+
return errors.Wrapf(err, "failed to load certificate %q", nickname)
92+
}
93+
94+
//nolint:gosec // openssl/pk12util args are from trusted config
95+
func (c *CertificateHandler) loadPrivateKey(ctx context.Context, certData, keyData []byte, nickname string) error {
96+
// Write cert and key to temporary files
97+
certFile, err := os.CreateTemp(RootDir, "submariner-cert-*.crt")
98+
if err != nil {
99+
return errors.Wrap(err, "failed to create temporary cert file")
101100
}
101+
defer os.Remove(certFile.Name())
102102

103-
return nil
104-
}
103+
if _, err := certFile.Write(certData); err != nil {
104+
return errors.Wrap(err, "failed to write certificate to temporary file")
105+
}
105106

106-
func (c *CertificateHandler) loadPrivateKey(ctx context.Context, keyData []byte, nickname string) error {
107-
execCmd := c.newCertUtilCmd(ctx, "-A", "-n", nickname, "-t", "u,u,u", "-i", "-", "-a")
108-
execCmd.Stdin = bytes.NewReader(keyData)
107+
certFile.Close()
109108

110-
cmd := command.New(execCmd)
109+
keyFile, err := os.CreateTemp(RootDir, "submariner-key-*.key")
110+
if err != nil {
111+
return errors.Wrap(err, "failed to create temporary key file")
112+
}
113+
defer os.Remove(keyFile.Name())
111114

112-
if err := execCertUtil(cmd); err != nil {
113-
return errors.Wrap(err, "failed to load private key")
115+
if _, err := keyFile.Write(keyData); err != nil {
116+
return errors.Wrap(err, "failed to write key to temporary file")
114117
}
115118

116-
return nil
119+
keyFile.Close()
120+
121+
// Create PKCS#12 file with openssl
122+
p12File, err := os.CreateTemp(RootDir, "submariner-client-*.p12")
123+
if err != nil {
124+
return errors.Wrap(err, "failed to create temporary pkcs12 file")
125+
}
126+
127+
defer os.Remove(p12File.Name())
128+
p12File.Close()
129+
130+
// Use empty password for PKCS#12
131+
pkcs12Password := ""
132+
133+
opensslCmd := exec.CommandContext(ctx, "openssl", "pkcs12", "-export",
134+
"-in", certFile.Name(),
135+
"-inkey", keyFile.Name(),
136+
"-out", p12File.Name(),
137+
"-name", nickname,
138+
"-passout", "pass:"+pkcs12Password)
139+
if err := execWithOutput(command.New(opensslCmd)); err != nil {
140+
return errors.Wrap(err, "failed to create PKCS#12 file")
141+
}
142+
143+
// Import PKCS#12 into NSS using pk12util
144+
pk12Cmd := exec.CommandContext(ctx, "pk12util", "-i", p12File.Name(), "-d", "sql:"+c.nssDBDir, "-W", pkcs12Password)
145+
err = execWithOutput(command.New(pk12Cmd))
146+
147+
return errors.Wrap(err, "failed to import PKCS#12 into NSS database")
117148
}
118149

119150
func (c *CertificateHandler) Cleanup(ctx context.Context) {
@@ -122,8 +153,8 @@ func (c *CertificateHandler) Cleanup(ctx context.Context) {
122153
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
123154
defer cancel()
124155

125-
for _, certName := range []string{CACertName, ClientCertName, ClientKeyName} {
126-
err := execCertUtil(command.New(c.newCertUtilCmd(ctx, "-D", "-n", certName)))
156+
for _, certName := range []string{CACertName, ClientCertName} {
157+
err := execWithOutput(command.New(c.newCertUtilCmd(ctx, "-D", "-n", certName)))
127158
if err != nil {
128159
certLogger.Errorf(err, "Failed to delete certificate %q from NSS database", certName)
129160
} else {
@@ -172,12 +203,16 @@ func (c *CertificateHandler) NSSDatabaseFile() string {
172203
return c.nssDBDir + "/cert9.db"
173204
}
174205

206+
func (c *CertificateHandler) NSSDatabaseDir() string {
207+
return c.nssDBDir
208+
}
209+
175210
func (c *CertificateHandler) newCertUtilCmd(ctx context.Context, args ...string) *exec.Cmd {
176211
//nolint:gosec // certutil args are from trusted config
177212
return exec.CommandContext(ctx, "certutil", append(args, "-d", "sql:"+c.nssDBDir)...)
178213
}
179214

180-
func execCertUtil(cmd command.Interface) error {
215+
func execWithOutput(cmd command.Interface) error {
181216
out, err := cmd.CombinedOutput()
182217
return errors.Wrapf(err, "failed to execute certutil: %s", string(out))
183218
}

pkg/cable/libreswan/certificate_handler_test.go

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ var _ = Describe("CertificateHandler", func() {
4949
setupTempDir()
5050

5151
cmdExecutor = fakecommand.New()
52-
handler = libreswan.NewCertificateHandler("test-cluster")
52+
handler = libreswan.NewCertificateHandler()
5353
Expect(handler).NotTo(BeNil())
5454
DeferCleanup(cmdExecutor.Clear)
5555
})
@@ -66,13 +66,11 @@ var _ = Describe("CertificateHandler", func() {
6666
It("should successfully load the certificates into the NSS database", func() {
6767
Expect(handler.OnSignedCallback(certData)).To(Succeed())
6868

69-
cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-N")
70-
assertCmdStdIn(cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-A", libreswan.CACertName),
71-
certData[certificate.CADataKey])
72-
assertCmdStdIn(cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-A", libreswan.ClientCertName),
73-
certData[certificate.TLSDataKey])
74-
assertCmdStdIn(cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-A", libreswan.ClientKeyName),
75-
certData[certificate.PrivateKeyDataKey])
69+
cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-N", "-d", "sql:"+handler.NSSDatabaseDir())
70+
assertCmdStdIn(cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-A", libreswan.CACertName,
71+
"-d", "sql:"+handler.NSSDatabaseDir()), certData[certificate.CADataKey])
72+
cmdExecutor.AwaitCommand(ContainSubstring("openssl"), "pkcs12", "-export", "-name", libreswan.ClientCertName)
73+
cmdExecutor.AwaitCommand(ContainSubstring("pk12util"), "-d", "sql:"+handler.NSSDatabaseDir())
7674
cmdExecutor.Clear()
7775

7876
By("Invoking OnSignedCallback with new cert data")
@@ -85,8 +83,6 @@ var _ = Describe("CertificateHandler", func() {
8583
Expect(handler.OnSignedCallback(newCertData)).To(Succeed())
8684

8785
cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-A", libreswan.CACertName)
88-
cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-A", libreswan.ClientCertName)
89-
cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-A", libreswan.ClientKeyName)
9086
cmdExecutor.Clear()
9187

9288
By("Invoking OnSignedCallback with unchanged cert data")
@@ -149,7 +145,6 @@ var _ = Describe("CertificateHandler", func() {
149145

150146
cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-D", libreswan.CACertName)
151147
cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-D", libreswan.ClientCertName)
152-
cmdExecutor.AwaitCommand(ContainSubstring("certutil"), "-D", libreswan.ClientKeyName)
153148
})
154149
})
155150
})

pkg/cable/libreswan/libreswan.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ func (i *libreswan) Init(ctx context.Context) error {
229229

230230
var err error
231231

232-
i.certificateHandler = NewCertificateHandler(i.localEndpoint.ClusterID)
232+
i.certificateHandler = NewCertificateHandler()
233233

234234
err = i.signingRequestor.Issue(ctx, "libreswan-"+i.localEndpoint.Hostname, sanIPs, i.certificateHandler.OnSignedCallback)
235235
if err != nil {

0 commit comments

Comments
 (0)