func addToKnownCertificates(block *pem.Block, keyData *KeyStoreData, addToKeystore bool) error {
	sha512str, err := getCertificateFingerprint(block)
	if err != nil {
		return err
	}
	known := false
	for _, fingerprint := range keyData.KnownFingerPrints {
		if fingerprint == sha512str {
			known = true
			break
		}
	}
	if !known {
		if addToKeystore {
			keyData.TrustedCerts = append(keyData.TrustedCerts, block)
		}
		keyData.KnownFingerPrints = append(keyData.KnownFingerPrints, sha512str)
	}
	return nil
}
addToKnownCertificates adds to the list of known certificates for a Keystore
package tls
import (
	"bufio"
	"fmt"
	"io/ioutil"
	pwr "math/rand"
	"os"
	"path/filepath"
	"strings"
	"time"
	"crypto/rand"
	"crypto/sha512"
	"crypto/x509"
	"encoding/pem"
	pkcs "software.sslmate.com/src/go-pkcs12"
	"github.com/ibm-messaging/mq-container/internal/keystore"
	"github.com/ibm-messaging/mq-container/internal/mqtemplate"
	"github.com/ibm-messaging/mq-container/pkg/logger"
)
const cmsKeystoreName = "key.kdb"
const p12TruststoreName = "trust.p12"
const keystoreDirDefault = "/run/runmqserver/tls/"
const keystoreDirHA = "/run/runmqserver/ha/tls/"
const keyDirDefault = "/etc/mqm/pki/keys"
const keyDirHA = "/etc/mqm/ha/pki/keys"
const trustDirDefault = "/etc/mqm/pki/trust"
type KeyStoreData struct {
	Keystore          *keystore.KeyStore
	Password          string
	TrustedCerts      []*pem.Block
	KnownFingerPrints []string
	KeyLabels         []string
}
type P12KeyFiles struct {
	Keystores []string
	Password  string
}
type TLSStore struct {
	Keystore   KeyStoreData
	Truststore KeyStoreData
}
func configureTLSKeystores(keystoreDir, keyDir, trustDir string, p12TruststoreRequired bool) (string, KeyStoreData, KeyStoreData, error) {
	tlsStore, err := generateAllKeystores(keystoreDir, p12TruststoreRequired)
	if err != nil {
		return "", tlsStore.Keystore, tlsStore.Truststore, err
	}
	keyLabel, err := processKeys(&tlsStore, keystoreDir, keyDir)
	if err != nil {
		return "", tlsStore.Keystore, tlsStore.Truststore, err
	}
	err = processTrustCertificates(&tlsStore, trustDir)
	if err != nil {
		return "", tlsStore.Keystore, tlsStore.Truststore, err
	}
	return keyLabel, tlsStore.Keystore, tlsStore.Truststore, err
}
func ConfigureDefaultTLSKeystores() (string, KeyStoreData, KeyStoreData, error) {
	return configureTLSKeystores(keystoreDirDefault, keyDirDefault, trustDirDefault, true)
}
func ConfigureHATLSKeystore() (string, KeyStoreData, KeyStoreData, error) {
	return configureTLSKeystores(keystoreDirHA, keyDirHA, keyDirHA, false)
}
func ConfigureTLS(keyLabel string, cmsKeystore KeyStoreData, devMode bool, log *logger.Logger) error {
	const mqsc string = "/etc/mqm/15-tls.mqsc"
	const mqscTemplate string = mqsc + ".tpl"
	err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
		"SSLKeyR":          strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb"),
		"CertificateLabel": keyLabel,
	}, log)
	if err != nil {
		return err
	}
	if devMode && keyLabel != "" {
		err = configureTLSDev(log)
		if err != nil {
			return err
		}
	}
	return nil
}
func configureTLSDev(log *logger.Logger) error {
	const mqsc string = "/etc/mqm/20-dev-tls.mqsc"
	const mqscTemplate string = mqsc + ".tpl"
	if os.Getenv("MQ_DEV") == "true" {
		err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{}, log)
		if err != nil {
			return err
		}
	} else {
		_, err := os.Stat(mqsc)
		if !os.IsNotExist(err) {
			err = os.Remove(mqsc)
			if err != nil {
				return fmt.Errorf("Failed to remove file %s: %v", mqsc, err)
			}
		}
	}
	return nil
}
func generateAllKeystores(keystoreDir string, p12TruststoreRequired bool) (TLSStore, error) {
	var cmsKeystore, p12Truststore KeyStoreData
	pw := generateRandomPassword()
	cmsKeystore.Password = pw
	p12Truststore.Password = pw
	err := os.MkdirAll(keystoreDir, 0770)
	if err != nil {
		return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create Keystore directory: %v", err)
	}
	cmsKeystore.Keystore = keystore.NewCMSKeyStore(filepath.Join(keystoreDir, cmsKeystoreName), cmsKeystore.Password)
	err = cmsKeystore.Keystore.Create()
	if err != nil {
		return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create CMS Keystore: %v", err)
	}
	if p12TruststoreRequired {
		p12Truststore.Keystore = keystore.NewPKCS12KeyStore(filepath.Join(keystoreDir, p12TruststoreName), p12Truststore.Password)
		err = p12Truststore.Keystore.Create()
		if err != nil {
			return TLSStore{cmsKeystore, p12Truststore}, fmt.Errorf("Failed to create PKCS#12 Truststore: %v", err)
		}
	}
	return TLSStore{cmsKeystore, p12Truststore}, nil
}
func processKeys(tlsStore *TLSStore, keystoreDir string, keyDir string) (string, error) {
	keyLabel := ""
	keyList, err := ioutil.ReadDir(keyDir)
	if err == nil && len(keyList) > 0 {
		for _, keySet := range keyList {
			keys, _ := ioutil.ReadDir(filepath.Join(keyDir, keySet.Name()))
			if keySet.Name() == p12TruststoreName[0:len(p12TruststoreName)-len(filepath.Ext(p12TruststoreName))] {
				return "", fmt.Errorf("Key label cannot be set to the Truststore name: %v", keySet.Name())
			}
			privateKey, keyPrefix, err := processPrivateKey(keyDir, keySet.Name(), keys)
			if err != nil {
				return "", err
			}
			if privateKey == nil {
				continue
			}
			publicCertificate, caCertificate, err := processCertificates(keyDir, keySet.Name(), keyPrefix, keys, &tlsStore.Keystore, &tlsStore.Truststore)
			if err != nil {
				return "", err
			}
			file, err := pkcs.Encode(rand.Reader, privateKey, publicCertificate, caCertificate, tlsStore.Keystore.Password)
			if err != nil {
				return "", fmt.Errorf("Failed to encode PKCS#12 Keystore %s: %v", keySet.Name()+".p12", err)
			}
			err = ioutil.WriteFile(filepath.Join(keystoreDir, keySet.Name()+".p12"), file, 0644)
			if err != nil {
				return "", fmt.Errorf("Failed to write PKCS#12 Keystore %s: %v", filepath.Join(keystoreDir, keySet.Name()+".p12"), err)
			}
			err = tlsStore.Keystore.Keystore.Import(filepath.Join(keystoreDir, keySet.Name()+".p12"), tlsStore.Keystore.Password)
			if err != nil {
				return "", fmt.Errorf("Failed to import keys from %s into CMS Keystore: %v", filepath.Join(keystoreDir, keySet.Name()+".p12"), err)
			}
			err = relabelCertificate(keySet.Name(), &tlsStore.Keystore)
			if err != nil {
				return "", err
			}
			if keyLabel == "" {
				keyLabel = keySet.Name()
			}
		}
	}
	return keyLabel, nil
}
func processTrustCertificates(tlsStore *TLSStore, trustDir string) error {
	trustList, err := ioutil.ReadDir(trustDir)
	if err == nil && len(trustList) > 0 {
		for _, trustSet := range trustList {
			keys, _ := ioutil.ReadDir(filepath.Join(trustDir, trustSet.Name()))
			for _, key := range keys {
				if strings.HasSuffix(key.Name(), ".crt") {
					file, err := ioutil.ReadFile(filepath.Join(trustDir, trustSet.Name(), key.Name()))
					if err != nil {
						return fmt.Errorf("Failed to read file %s: %v", filepath.Join(trustDir, trustSet.Name(), key.Name()), err)
					}
					for string(file) != "" {
						var block *pem.Block
						block, file = pem.Decode(file)
						if block == nil {
							break
						}
						err = addToKnownCertificates(block, &tlsStore.Keystore, true)
						if err != nil {
							return fmt.Errorf("Failed to add to know certificates for CMS Keystore")
						}
						if tlsStore.Truststore.Keystore != nil {
							err = addToKnownCertificates(block, &tlsStore.Truststore, true)
							if err != nil {
								return fmt.Errorf("Failed to add to know certificates for PKCS#12 Truststore")
							}
						}
					}
				}
			}
		}
	}
	if tlsStore.Truststore.Keystore != nil && len(tlsStore.Truststore.TrustedCerts) > 0 {
		err = addCertificatesToTruststore(&tlsStore.Truststore)
		if err != nil {
			return err
		}
	}
	if len(tlsStore.Keystore.TrustedCerts) > 0 {
		err = addCertificatesToCMSKeystore(&tlsStore.Keystore)
		if err != nil {
			return err
		}
	}
	return nil
}
func processPrivateKey(keyDir string, keySetName string, keys []os.FileInfo) (interface{}, string, error) {
	var privateKey interface{}
	keyPrefix := ""
	for _, key := range keys {
		if strings.HasSuffix(key.Name(), ".key") {
			file, err := ioutil.ReadFile(filepath.Join(keyDir, keySetName, key.Name()))
			if err != nil {
				return nil, "", fmt.Errorf("Failed to read private key %s: %v", filepath.Join(keyDir, keySetName, key.Name()), err)
			}
			block, _ := pem.Decode(file)
			if block == nil {
				return nil, "", fmt.Errorf("Failed to decode private key %s: pem.Decode returned nil", filepath.Join(keyDir, keySetName, key.Name()))
			}
			privateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
			if err != nil {
				privateKey, err = x509.ParsePKCS8PrivateKey(block.Bytes)
				if err != nil {
					return nil, "", fmt.Errorf("Failed to parse private key %s: %v", filepath.Join(keyDir, keySetName, key.Name()), err)
				}
			}
			keyPrefix = key.Name()[0 : len(key.Name())-len(filepath.Ext(key.Name()))]
		}
	}
	return privateKey, keyPrefix, nil
}
func processCertificates(keyDir string, keySetName, keyPrefix string, keys []os.FileInfo, cmsKeystore, p12Truststore *KeyStoreData) (*x509.Certificate, []*x509.Certificate, error) {
	var publicCertificate *x509.Certificate
	var caCertificate []*x509.Certificate
	for _, key := range keys {
		if strings.HasPrefix(key.Name(), keyPrefix) && strings.HasSuffix(key.Name(), ".crt") {
			file, err := ioutil.ReadFile(filepath.Join(keyDir, keySetName, key.Name()))
			if err != nil {
				return nil, nil, fmt.Errorf("Failed to read public certificate %s: %v", filepath.Join(keyDir, keySetName, key.Name()), err)
			}
			block, _ := pem.Decode(file)
			if block == nil {
				return nil, nil, fmt.Errorf("Failed to decode public certificate %s: pem.Decode returned nil", filepath.Join(keyDir, keySetName, key.Name()))
			}
			publicCertificate, err = x509.ParseCertificate(block.Bytes)
			if err != nil {
				return nil, nil, fmt.Errorf("Failed to parse public certificate %s: %v", filepath.Join(keyDir, keySetName, key.Name()), err)
			}
			err = addToKnownCertificates(block, cmsKeystore, false)
			if err != nil {
				return nil, nil, fmt.Errorf("Failed to add to know certificates for CMS Keystore")
			}
		} else if strings.HasSuffix(key.Name(), ".crt") {
			file, err := ioutil.ReadFile(filepath.Join(keyDir, keySetName, key.Name()))
			if err != nil {
				return nil, nil, fmt.Errorf("Failed to read CA certificate %s: %v", filepath.Join(keyDir, keySetName, key.Name()), err)
			}
			for string(file) != "" {
				var block *pem.Block
				block, file = pem.Decode(file)
				if block == nil {
					break
				}
				err = addToKnownCertificates(block, cmsKeystore, false)
				if err != nil {
					return nil, nil, fmt.Errorf("Failed to add to know certificates for CMS Keystore")
				}
				if p12Truststore.Keystore != nil {
					err = addToKnownCertificates(block, p12Truststore, true)
					if err != nil {
						return nil, nil, fmt.Errorf("Failed to add to know certificates for PKCS#12 Truststore")
					}
				}
				certificate, err := x509.ParseCertificate(block.Bytes)
				if err != nil {
					return nil, nil, fmt.Errorf("Failed to parse CA certificate %s: %v", filepath.Join(keyDir, keySetName, key.Name()), err)
				}
				caCertificate = append(caCertificate, certificate)
			}
		}
	}
	return publicCertificate, caCertificate, nil
}
func relabelCertificate(newLabel string, cmsKeystore *KeyStoreData) error {
	allLabels, err := cmsKeystore.Keystore.GetCertificateLabels()
	if err != nil {
		return fmt.Errorf("Failed to get list of all certificate labels from CMS Keystore: %v", err)
	}
	relabelled := false
	for _, label := range allLabels {
		found := false
		for _, keyLabel := range cmsKeystore.KeyLabels {
			if strings.Trim(label, "\"") == keyLabel {
				found = true
				break
			}
		}
		if !found {
			err = cmsKeystore.Keystore.RenameCertificate(strings.Trim(label, "\""), newLabel)
			if err != nil {
				return err
			}
			relabelled = true
			cmsKeystore.KeyLabels = append(cmsKeystore.KeyLabels, newLabel)
			break
		}
	}
	if !relabelled {
		return fmt.Errorf("Failed to relabel certificate for %s in CMS keystore", newLabel)
	}
	return nil
}
func addCertificatesToTruststore(p12Truststore *KeyStoreData) error {
	temporaryPemFile := filepath.Join("/tmp", "trust.pem")
	_, err := os.Stat(temporaryPemFile)
	if err == nil {
		err = os.Remove(temporaryPemFile)
		if err != nil {
			return fmt.Errorf("Failed to remove file %v: %v", temporaryPemFile, err)
		}
	}
	err = writeCertificatesToFile(temporaryPemFile, p12Truststore.TrustedCerts)
	if err != nil {
		return err
	}
	err = p12Truststore.Keystore.AddNoLabel(temporaryPemFile)
	if err != nil {
		return fmt.Errorf("Failed to add certificates to PKCS#12 Truststore: %v", err)
	}
	allCertificates, err := p12Truststore.Keystore.ListAllCertificates()
	if err != nil || len(allCertificates) <= 0 {
		return fmt.Errorf("Failed to get any certificates from PKCS#12 Truststore: %v", err)
	}
	for i, certificate := range allCertificates {
		certificate = strings.Trim(certificate, "\"")
		certificate = strings.TrimSpace(certificate)
		newLabel := fmt.Sprintf("Trust%d", i)
		err = p12Truststore.Keystore.RenameCertificate(certificate, newLabel)
		if err != nil || len(allCertificates) <= 0 {
			return fmt.Errorf("Failed to rename certificate %s to %s in PKCS#12 Truststore: %v", certificate, newLabel, err)
		}
	}
	return nil
}
func addCertificatesToCMSKeystore(cmsKeystore *KeyStoreData) error {
	temporaryPemFile := filepath.Join("/tmp", "cmsTrust.pem")
	_, err := os.Stat(temporaryPemFile)
	if err == nil {
		err = os.Remove(temporaryPemFile)
		if err != nil {
			return fmt.Errorf("Failed to remove file %v: %v", temporaryPemFile, err)
		}
	}
	err = writeCertificatesToFile(temporaryPemFile, cmsKeystore.TrustedCerts)
	if err != nil {
		return err
	}
	err = cmsKeystore.Keystore.AddNoLabel(temporaryPemFile)
	if err != nil {
		return fmt.Errorf("Failed to add certificates to CMS keystore: %v", err)
	}
	return nil
}
func generateRandomPassword() string {
	pwr.Seed(time.Now().Unix())
	validChars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
	validcharArray := []byte(validChars)
	password := ""
	for i := 0; i < 12; i++ {
		password = password + string(validcharArray[pwr.Intn(len(validcharArray))])
	}
	return password
}