@@ -17,9 +17,12 @@ limitations under the License.
1717package truststore
1818
1919import (
20+ "bytes"
2021 "crypto/sha256"
2122 "encoding/hex"
23+ "fmt"
2224
25+ "github.com/pavlo-v-chernykh/keystore-go/v4"
2326 "software.sslmate.com/src/go-pkcs12"
2427
2528 "github.com/cert-manager/trust-manager/pkg/apis/trust/v1alpha1"
@@ -31,7 +34,52 @@ type Encoder interface {
3134}
3235
3336func NewJKSEncoder (password string ) Encoder {
34- return NewPKCS12Encoder (password , v1alpha1 .LegacyRC2PKCS12Profile )
37+ return & jksEncoder {password : password }
38+ }
39+
40+ type jksEncoder struct {
41+ password string
42+ }
43+
44+ // Encode creates a binary JKS file from the given PEM-encoded trust bundle and Password.
45+ // Note that the Password is not treated securely; JKS files generally seem to expect a Password
46+ // to exist and so we have the option for one.
47+ func (e jksEncoder ) Encode (trustBundle * util.CertPool ) ([]byte , error ) {
48+ // WithOrderedAliases ensures that trusted certs are added to the JKS file in order,
49+ // which makes the files appear to be reliably deterministic.
50+ ks := keystore .New (keystore .WithOrderedAliases ())
51+
52+ for _ , c := range trustBundle .Certificates () {
53+ alias := certAlias (c .Raw , c .Subject .String ())
54+
55+ // Note on CreationTime:
56+ // Debian's JKS trust store sets the creation time to match the time that certs are added to the
57+ // trust store (i.e., it's effectively time.Now() at the instant the file is generated).
58+ // Using that method would make our JKS files in trust-manager non-deterministic, leaving us with
59+ // two options if we want to maintain determinism:
60+ // - Using something from the cert being added (e.g. NotBefore / NotAfter)
61+ // - Using a fixed time (i.e. unix epoch)
62+ // We use NotBefore here, arbitrarily.
63+
64+ if err := ks .SetTrustedCertificateEntry (alias , keystore.TrustedCertificateEntry {
65+ CreationTime : c .NotBefore ,
66+ Certificate : keystore.Certificate {
67+ Type : "X509" ,
68+ Content : c .Raw ,
69+ },
70+ }); err != nil {
71+ // this error should never happen if we set jks.Certificate correctly
72+ return nil , fmt .Errorf ("failed to add cert with alias %q to trust store: %w" , alias , err )
73+ }
74+ }
75+
76+ buf := & bytes.Buffer {}
77+
78+ if err := ks .Store (buf , []byte (e .password )); err != nil {
79+ return nil , fmt .Errorf ("failed to create JKS file: %w" , err )
80+ }
81+
82+ return buf .Bytes (), nil
3583}
3684
3785func NewPKCS12Encoder (password string , profile v1alpha1.PKCS12Profile ) Encoder {
0 commit comments