package internal import ( "bytes" "crypto/rand" "crypto/x509" "time" utilpki "gitbucket.jerxie.com/yangyangxie/AnthosCertManager/pkg/util/pki" jks "github.com/pavlo-v-chernykh/keystore-go/v4" "software.sslmate.com/src/go-pkcs12" ) const ( // pkcs12SecretKey is the name of the data entry in the Secret resource // used to store the p12 file. pkcs12SecretKey = "keystore.p12" // Data Entry Name in the Secret resource for PKCS12 containing Certificate Authority pkcs12TruststoreKey = "truststore.p12" // jksSecretKey is the name of the data entry in the Secret resource // used to store the jks file. jksSecretKey = "keystore.jks" // Data Entry Name in the Secret resource for JKS containing Certificate Authority jksTruststoreKey = "truststore.jks" ) // encodePKCS12Keystore will encode a PKCS12 keystore using the password provided. // The key, certificate and CA data must be provided in PKCS1 or PKCS8 PEM format. // If the certificate data contains multiple certificates, the first will be used // as the keystores 'certificate' and the remaining certificates will be prepended // to the list of CAs in the resulting keystore. func encodePKCS12Keystore(password string, rawKey []byte, certPem []byte, caPem []byte) ([]byte, error) { key, err := utilpki.DecodePrivateKeyBytes(rawKey) if err != nil { return nil, err } certs, err := utilpki.DecodeX509CertificateChainBytes(certPem) if err != nil { return nil, err } var cas []*x509.Certificate if len(caPem) > 0 { cas, err = utilpki.DecodeX509CertificateChainBytes(caPem) if err != nil { return nil, err } } // prepend the certificate chain to the list of certificates as the PKCS12 // library only allows setting a single certificate. if len(certs) > 1 { cas = append(certs[1:], cas...) } return pkcs12.Encode(rand.Reader, key, certs[0], cas, password) } // encode the ca certificate func encodePKCS12Truststore(password string, caPem []byte) ([]byte, error) { ca, err := utilpki.DecodeX509CertificateBytes(caPem) if err != nil { return nil, err } var cas = []*x509.Certificate{ca} return pkcs12.EncodeTrustStore(rand.Reader, cas, password) } // encode java key store. Input the PEM data and return the raw data of the DER file being protected by the given password func encodeJKSKeystore(password []byte, rawKey []byte, certPem []byte, caPem []byte) ([]byte, error) { ks := jks.New() // add the private key if err := setJKSPrivateKey(&ks, password, rawKey, certPem); err != nil { return nil, err } // add the CA certificate if set if len(caPem) > 0 { if err := setJKSTruststore(&ks, caPem); err != nil { return nil, err } } buf := &bytes.Buffer{} if err := ks.Store(buf, password); err != nil { return nil, err } return buf.Bytes(), nil } func encodeJKSTruststore(password []byte, caPem []byte) ([]byte, error) { ks := jks.New() if err := setJKSTruststore(&ks, caPem); err != nil { return nil, err } buf := &bytes.Buffer{} if err := ks.Store(buf, password); err != nil { return nil, err } return buf.Bytes(), nil } func setJKSTruststore(ks *jks.KeyStore, caPem []byte) error { ca, err := utilpki.DecodeX509CertificateBytes(caPem) if err != nil { return err } ks.SetTrustedCertificateEntry("ca", jks.TrustedCertificateEntry{ CreationTime: time.Now(), Certificate: jks.Certificate{ Type: "X509", Content: ca.Raw, }, }) return nil } func setJKSPrivateKey(ks *jks.KeyStore, password []byte, rawKey []byte, certPem []byte) error { // convert the private key to PKCS8 key, err := utilpki.DecodePrivateKeyBytes(rawKey) if err != nil { return err } keyDER, err := x509.MarshalPKCS8PrivateKey(key) if err != nil { return err } // convert the certificate chain chain, err := utilpki.DecodeX509CertificateChainBytes(certPem) if err != nil { return err } certs := make([]jks.Certificate, len(chain)) for i, cert := range chain { certs[i] = jks.Certificate{Type: "X509", Content: cert.Raw} } ks.SetPrivateKeyEntry("certificate", jks.PrivateKeyEntry{ CreationTime: time.Now(), PrivateKey: keyDER, CertificateChain: certs, }, password) return nil }