@@ -39,20 +39,17 @@ var certLogger = log.Logger{Logger: logf.Log.WithName("CertHandler")}
3939const (
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.
4645type 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
7673func (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
9385func (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
119150func (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+
175210func (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}
0 commit comments