PR for FIPS implemenation (#351)
* Part 1 of FIPS Compliance * MQ Web Server FIPSs changes * Remove function param * Updates to FIPS MQ WebServer * Fix build error * Merge latest code from private-master * Rename fips variable * Fix build break * Fix build break * Fix build break * Add new docker tests * First cut of fips metrics * First cut of fips metrics * Second part of metrics fips * Second part of metrics fips * Added NativeHA FIPS * Updated test * Add Native HA tests * Optimze FIPS handling * Update comments * Apply changes from private-master * Undo metrics changes * Merge latest changes * Pull in changes from master * Update copyright year * Resolve merge conflicts
This commit is contained in:
committed by
GitHub Enterprise
parent
1ead807326
commit
794d1ed2b2
2
Makefile
2
Makefile
@@ -48,7 +48,7 @@ MQ_SDK_ARCHIVE ?= $(MQ_ARCHIVE_DEV_$(MQ_VERSION))
|
|||||||
# Options to `go test` for the Docker tests
|
# Options to `go test` for the Docker tests
|
||||||
TEST_OPTS_DOCKER ?=
|
TEST_OPTS_DOCKER ?=
|
||||||
# Timeout for the Docker tests
|
# Timeout for the Docker tests
|
||||||
TEST_TIMEOUT_DOCKER ?= 30m
|
TEST_TIMEOUT_DOCKER ?= 45m
|
||||||
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
|
# MQ_IMAGE_ADVANCEDSERVER is the name of the built MQ Advanced image
|
||||||
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
|
MQ_IMAGE_ADVANCEDSERVER ?=ibm-mqadvanced-server
|
||||||
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
|
# MQ_IMAGE_DEVSERVER is the name of the built MQ Advanced for Developers image
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2017, 2021
|
© Copyright IBM Corporation 2017, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/fips"
|
||||||
"github.com/ibm-messaging/mq-container/internal/ha"
|
"github.com/ibm-messaging/mq-container/internal/ha"
|
||||||
"github.com/ibm-messaging/mq-container/internal/metrics"
|
"github.com/ibm-messaging/mq-container/internal/metrics"
|
||||||
"github.com/ibm-messaging/mq-container/internal/ready"
|
"github.com/ibm-messaging/mq-container/internal/ready"
|
||||||
@@ -144,6 +145,9 @@ func doMain() error {
|
|||||||
// Print out versioning information
|
// Print out versioning information
|
||||||
logVersionInfo()
|
logVersionInfo()
|
||||||
|
|
||||||
|
// Determine FIPS compliance level
|
||||||
|
fips.ProcessFIPSType(log)
|
||||||
|
|
||||||
keyLabel, defaultCmsKeystore, defaultP12Truststore, err := tls.ConfigureDefaultTLSKeystores()
|
keyLabel, defaultCmsKeystore, defaultP12Truststore, err := tls.ConfigureDefaultTLSKeystores()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logTermination(err)
|
logTermination(err)
|
||||||
@@ -170,6 +174,14 @@ func doMain() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Log a message on the console to indicate FIPS certified
|
||||||
|
// cryptography being used.
|
||||||
|
if fips.IsFIPSEnabled() {
|
||||||
|
log.Println("FIPS cryptography is enabled.")
|
||||||
|
} else {
|
||||||
|
log.Println("FIPS cryptography is not enabled.")
|
||||||
|
}
|
||||||
|
|
||||||
enableTraceCrtmqm := os.Getenv("MQ_ENABLE_TRACE_CRTMQM")
|
enableTraceCrtmqm := os.Getenv("MQ_ENABLE_TRACE_CRTMQM")
|
||||||
if enableTraceCrtmqm == "true" || enableTraceCrtmqm == "1" {
|
if enableTraceCrtmqm == "true" || enableTraceCrtmqm == "1" {
|
||||||
err = startMQTrace()
|
err = startMQTrace()
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2019
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -18,6 +18,7 @@ package main
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/fips"
|
||||||
"github.com/ibm-messaging/mq-container/internal/tls"
|
"github.com/ibm-messaging/mq-container/internal/tls"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -35,6 +36,15 @@ func postInit(name, keyLabel string, p12Truststore tls.KeyStoreData) error {
|
|||||||
if len(p12Truststore.TrustedCerts) == 0 {
|
if len(p12Truststore.TrustedCerts) == 0 {
|
||||||
webTruststoreRef = "MQWebKeyStore"
|
webTruststoreRef = "MQWebKeyStore"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Enable FIPS for MQ Web Server if asked for.
|
||||||
|
if fips.IsFIPSEnabled() {
|
||||||
|
err = configureFIPSWebServer(p12Truststore)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Start the web server, in the background (if installed)
|
// Start the web server, in the background (if installed)
|
||||||
// WARNING: No error handling or health checking available for the web server
|
// WARNING: No error handling or health checking available for the web server
|
||||||
go func() {
|
go func() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2018, 2020
|
© Copyright IBM Corporation 2018, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -197,3 +197,25 @@ func configureWebServer(keyLabel string, p12Truststore tls.KeyStoreData) (string
|
|||||||
|
|
||||||
return webKeystore, err
|
return webKeystore, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Configure FIPS mode for MQ Web Server
|
||||||
|
func configureFIPSWebServer(p12TrustStore tls.KeyStoreData) error {
|
||||||
|
var errOut error
|
||||||
|
// Need to update jvm.options file of MQ Web Server. We don't update the jvm.options file
|
||||||
|
// in /var/mqm/web/installations/Installation1/servers/mqweb directory. Instead we update
|
||||||
|
// the one in /var/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults.
|
||||||
|
// During runtime MQ Web Server merges the data from two files.
|
||||||
|
mqwebJvmOptsDir := "/var/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults"
|
||||||
|
_, errOut = os.Stat(mqwebJvmOptsDir)
|
||||||
|
if errOut == nil {
|
||||||
|
// Update the jvm.options file using the data from template file. Tell the MQ Web Server
|
||||||
|
// use a FIPS provider by setting "-Dcom.ibm.jsse2.usefipsprovider=true" and then tell it
|
||||||
|
// use a specific FIPS provider by setting "Dcom.ibm.jsse2.usefipsProviderName=IBMJCEPlusFIPS".
|
||||||
|
errOut = mqtemplate.ProcessTemplateFile(mqwebJvmOptsDir+"/jvm.options.tpl",
|
||||||
|
mqwebJvmOptsDir+"/jvm.options", map[string]string{
|
||||||
|
"FipsProvider": "true",
|
||||||
|
"FipsProviderName": "IBMJCEPlusFIPS",
|
||||||
|
}, log)
|
||||||
|
}
|
||||||
|
return errOut
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
* © Copyright IBM Corporation 2019
|
* © Copyright IBM Corporation 2019, 2022
|
||||||
*
|
*
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@@ -16,4 +16,5 @@
|
|||||||
* Set the keystore location for the queue manager
|
* Set the keystore location for the queue manager
|
||||||
ALTER QMGR SSLKEYR('{{ .SSLKeyR }}')
|
ALTER QMGR SSLKEYR('{{ .SSLKeyR }}')
|
||||||
ALTER QMGR CERTLABL('{{ .CertificateLabel }}')
|
ALTER QMGR CERTLABL('{{ .CertificateLabel }}')
|
||||||
|
ALTER QMGR SSLFIPS({{ .SSLFips }})
|
||||||
REFRESH SECURITY(*) TYPE(SSL)
|
REFRESH SECURITY(*) TYPE(SSL)
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ NativeHALocalInstance:
|
|||||||
{{ if .CipherSpec }}
|
{{ if .CipherSpec }}
|
||||||
CipherSpec={{ .CipherSpec }}
|
CipherSpec={{ .CipherSpec }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
|
{{ if .SSLFipsRequired }}
|
||||||
|
SSLFipsRequired={{ .SSLFipsRequired }}
|
||||||
|
{{- end }}
|
||||||
{{- end }}
|
{{- end }}
|
||||||
NativeHAInstance:
|
NativeHAInstance:
|
||||||
Name={{ .NativeHAInstance0_Name }}
|
Name={{ .NativeHAInstance0_Name }}
|
||||||
|
|||||||
78
internal/fips/fips.go
Normal file
78
internal/fips/fips.go
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2022
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
package fips
|
||||||
|
|
||||||
|
import (
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
|
"github.com/ibm-messaging/mq-container/pkg/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
FIPSEnabledType int
|
||||||
|
)
|
||||||
|
|
||||||
|
// FIPS has been turned off either because OS is not FIPS enabled or
|
||||||
|
// MQ_ENABLE_FIPS environment variable is set to "false"
|
||||||
|
const FIPS_ENABLED_OFF = 0
|
||||||
|
|
||||||
|
// FIPS is turned ON
|
||||||
|
const FIPS_ENABLED_ON = 1
|
||||||
|
|
||||||
|
// FIPS enabled at operating system level
|
||||||
|
const FIPS_ENABLED_PLATFORM = 1
|
||||||
|
|
||||||
|
// FIPS enabled via environment variable
|
||||||
|
const FIPS_ENABLED_ENV_VAR = 2
|
||||||
|
|
||||||
|
// Get FIPS enabled type.
|
||||||
|
func ProcessFIPSType(logs *logger.Logger) {
|
||||||
|
// Run "sysctl crypto.fips_enabled" command to determine if FIPS has been enabled
|
||||||
|
// on OS.
|
||||||
|
FIPSEnabledType = FIPS_ENABLED_OFF
|
||||||
|
out, _, err := command.Run("sysctl", "crypto.fips_enabled")
|
||||||
|
if err == nil {
|
||||||
|
// Check the output of the command for expected output
|
||||||
|
if strings.Contains(out, "crypto.fips_enabled = 1") {
|
||||||
|
FIPSEnabledType = FIPS_ENABLED_PLATFORM
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we have been asked to override FIPS cryptography
|
||||||
|
fipsOverride, fipsOverrideSet := os.LookupEnv("MQ_ENABLE_FIPS")
|
||||||
|
if fipsOverrideSet {
|
||||||
|
if strings.EqualFold(fipsOverride, "false") || strings.EqualFold(fipsOverride, "0") {
|
||||||
|
FIPSEnabledType = FIPS_ENABLED_OFF
|
||||||
|
} else if strings.EqualFold(fipsOverride, "true") || strings.EqualFold(fipsOverride, "1") {
|
||||||
|
// This is the case where OS is not FIPS compliant but we have been asked to run MQ
|
||||||
|
// queue manager, web server in FIPS mode. This case can be used when running docker tests.
|
||||||
|
FIPSEnabledType = FIPS_ENABLED_ENV_VAR
|
||||||
|
} else if strings.EqualFold(fipsOverride, "auto") {
|
||||||
|
// This is the default case. Leave it to the OS default as determine above
|
||||||
|
} else {
|
||||||
|
// We don't recognise the value specified. Log a warning and carry on.
|
||||||
|
if logs != nil {
|
||||||
|
logs.Printf("Invalid value '%s' was specified for MQ_ENABLE_FIPS. The value has been ignored.\n", fipsOverride)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func IsFIPSEnabled() bool {
|
||||||
|
return FIPSEnabledType > FIPS_ENABLED_OFF
|
||||||
|
}
|
||||||
65
internal/fips/fips_test.go
Normal file
65
internal/fips/fips_test.go
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/*
|
||||||
|
© Copyright IBM Corporation 2022
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Package keystore contains code to create and update keystores
|
||||||
|
package fips
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEnableFIPSAuto(t *testing.T) {
|
||||||
|
ProcessFIPSType(nil)
|
||||||
|
// Test default "auto"
|
||||||
|
fipsType := IsFIPSEnabled()
|
||||||
|
if fipsType {
|
||||||
|
t.Errorf("Expected FIPS OFF but got %v\n", fipsType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnableFIPSTrue(t *testing.T) {
|
||||||
|
// Test MQ_ENABLE_FIPS=true
|
||||||
|
os.Setenv("MQ_ENABLE_FIPS", "true")
|
||||||
|
fmt.Println(os.Getenv("MQ_ENABLE_FIPS"))
|
||||||
|
ProcessFIPSType(nil)
|
||||||
|
fipsType := IsFIPSEnabled()
|
||||||
|
if !fipsType {
|
||||||
|
t.Errorf("Expected FIPS ON but got %v\n", fipsType)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnableFIPSFalse(t *testing.T) {
|
||||||
|
// Test MQ_ENABLE_FIPS=false
|
||||||
|
os.Setenv("MQ_ENABLE_FIPS", "false")
|
||||||
|
ProcessFIPSType(nil)
|
||||||
|
fipsType := IsFIPSEnabled()
|
||||||
|
if fipsType {
|
||||||
|
t.Errorf("Expected FIPS OFF but got %v\n", fipsType)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnableFIPSInvalid(t *testing.T) {
|
||||||
|
// Test MQ_ENABLE_FIPS with invalid value
|
||||||
|
os.Setenv("MQ_ENABLE_FIPS", "falseOff")
|
||||||
|
ProcessFIPSType(nil)
|
||||||
|
fipsType := IsFIPSEnabled()
|
||||||
|
if fipsType {
|
||||||
|
t.Errorf("Expected FIPS OFF but got %v\n", fipsType)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
© Copyright IBM Corporation 2020, 2021
|
© Copyright IBM Corporation 2020, 2022
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
@@ -20,6 +20,7 @@ package ha
|
|||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/fips"
|
||||||
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
|
"github.com/ibm-messaging/mq-container/internal/mqtemplate"
|
||||||
"github.com/ibm-messaging/mq-container/internal/tls"
|
"github.com/ibm-messaging/mq-container/internal/tls"
|
||||||
"github.com/ibm-messaging/mq-container/pkg/logger"
|
"github.com/ibm-messaging/mq-container/pkg/logger"
|
||||||
@@ -57,6 +58,13 @@ func ConfigureNativeHA(log *logger.Logger) error {
|
|||||||
if ok {
|
if ok {
|
||||||
templateMap["CipherSpec"] = cipherSpec
|
templateMap["CipherSpec"] = cipherSpec
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If FIPS is enabled, then set SSLFipsRequired to Yes
|
||||||
|
if fips.IsFIPSEnabled() {
|
||||||
|
templateMap["SSLFipsRequired"] = "Yes"
|
||||||
|
} else {
|
||||||
|
templateMap["SSLFipsRequired"] = "No"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err := mqtemplate.ProcessTemplateFile(templateFile, file, templateMap, log)
|
err := mqtemplate.ProcessTemplateFile(templateFile, file, templateMap, log)
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/ibm-messaging/mq-container/internal/command"
|
"github.com/ibm-messaging/mq-container/internal/command"
|
||||||
|
"github.com/ibm-messaging/mq-container/internal/fips"
|
||||||
)
|
)
|
||||||
|
|
||||||
// KeyStore describes information about a keystore file
|
// KeyStore describes information about a keystore file
|
||||||
@@ -34,36 +35,46 @@ type KeyStore struct {
|
|||||||
Password string
|
Password string
|
||||||
keyStoreType string
|
keyStoreType string
|
||||||
command string
|
command string
|
||||||
|
fipsEnabled bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewJKSKeyStore creates a new Java Key Store, managed by the runmqckm command
|
// NewJKSKeyStore creates a new Java Key Store, managed by the runmqckm command
|
||||||
func NewJKSKeyStore(filename, password string) *KeyStore {
|
func NewJKSKeyStore(filename, password string) *KeyStore {
|
||||||
return &KeyStore{
|
keyStore := &KeyStore{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Password: password,
|
Password: password,
|
||||||
keyStoreType: "jks",
|
keyStoreType: "jks",
|
||||||
command: "/opt/mqm/bin/runmqckm",
|
command: "/opt/mqm/bin/runmqckm",
|
||||||
|
fipsEnabled: fips.IsFIPSEnabled(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return keyStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCMSKeyStore creates a new MQ CMS Key Store, managed by the runmqakm command
|
// NewCMSKeyStore creates a new MQ CMS Key Store, managed by the runmqakm command
|
||||||
func NewCMSKeyStore(filename, password string) *KeyStore {
|
func NewCMSKeyStore(filename, password string) *KeyStore {
|
||||||
return &KeyStore{
|
keyStore := &KeyStore{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Password: password,
|
Password: password,
|
||||||
keyStoreType: "cms",
|
keyStoreType: "cms",
|
||||||
command: "/opt/mqm/bin/runmqakm",
|
command: "/opt/mqm/bin/runmqakm",
|
||||||
|
fipsEnabled: fips.IsFIPSEnabled(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return keyStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPKCS12KeyStore creates a new PKCS12 Key Store, managed by the runmqakm command
|
// NewPKCS12KeyStore creates a new PKCS12 Key Store, managed by the runmqakm command
|
||||||
func NewPKCS12KeyStore(filename, password string) *KeyStore {
|
func NewPKCS12KeyStore(filename, password string) *KeyStore {
|
||||||
return &KeyStore{
|
keyStore := &KeyStore{
|
||||||
Filename: filename,
|
Filename: filename,
|
||||||
Password: password,
|
Password: password,
|
||||||
keyStoreType: "p12",
|
keyStoreType: "p12",
|
||||||
command: "/opt/mqm/bin/runmqakm",
|
command: "/opt/mqm/bin/runmqakm",
|
||||||
|
fipsEnabled: fips.IsFIPSEnabled(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return keyStore
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a key store, if it doesn't already exist
|
// Create a key store, if it doesn't already exist
|
||||||
@@ -100,7 +111,7 @@ func (ks *KeyStore) Create() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create the keystore now we're sure it doesn't exist
|
// Create the keystore now we're sure it doesn't exist
|
||||||
out, _, err := command.Run(ks.command, "-keydb", "-create", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password, "-stash")
|
out, _, err := command.Run(ks.command, "-keydb", "-create", ks.getFipsEnabledFlag(), "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password, "-stash")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -keydb -create\": %v %s", ks.command, err, out)
|
return fmt.Errorf("error running \"%v -keydb -create\": %v %s", ks.command, err, out)
|
||||||
}
|
}
|
||||||
@@ -115,7 +126,7 @@ func (ks *KeyStore) CreateStash() error {
|
|||||||
_, err := os.Stat(stashFile)
|
_, err := os.Stat(stashFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
out, _, err := command.Run(ks.command, "-keydb", "-stashpw", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
|
out, _, err := command.Run(ks.command, "-keydb", ks.getFipsEnabledFlag(), "-stashpw", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -keydb -stashpw\": %v %s", ks.command, err, out)
|
return fmt.Errorf("error running \"%v -keydb -stashpw\": %v %s", ks.command, err, out)
|
||||||
}
|
}
|
||||||
@@ -127,7 +138,7 @@ func (ks *KeyStore) CreateStash() error {
|
|||||||
|
|
||||||
// Import imports a certificate file in the keystore
|
// Import imports a certificate file in the keystore
|
||||||
func (ks *KeyStore) Import(inputFile, password string) error {
|
func (ks *KeyStore) Import(inputFile, password string) error {
|
||||||
out, _, err := command.Run(ks.command, "-cert", "-import", "-file", inputFile, "-pw", password, "-target", ks.Filename, "-target_pw", ks.Password, "-target_type", ks.keyStoreType)
|
out, _, err := command.Run(ks.command, "-cert", "-import", ks.getFipsEnabledFlag(), "-file", inputFile, "-pw", password, "-target", ks.Filename, "-target_pw", ks.Password, "-target_type", ks.keyStoreType)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -cert -import\": %v %s", ks.command, err, out)
|
return fmt.Errorf("error running \"%v -cert -import\": %v %s", ks.command, err, out)
|
||||||
}
|
}
|
||||||
@@ -136,7 +147,7 @@ func (ks *KeyStore) Import(inputFile, password string) error {
|
|||||||
|
|
||||||
// CreateSelfSignedCertificate creates a self-signed certificate in the keystore
|
// CreateSelfSignedCertificate creates a self-signed certificate in the keystore
|
||||||
func (ks *KeyStore) CreateSelfSignedCertificate(label, dn, hostname string) error {
|
func (ks *KeyStore) CreateSelfSignedCertificate(label, dn, hostname string) error {
|
||||||
out, _, err := command.Run(ks.command, "-cert", "-create", "-db", ks.Filename, "-pw", ks.Password, "-label", label, "-dn", dn, "-san_dnsname", hostname, "-size 2048 -sig_alg sha256 -eku serverAuth")
|
out, _, err := command.Run(ks.command, "-cert", "-create", ks.getFipsEnabledFlag(), "-db", ks.Filename, "-pw", ks.Password, "-label", label, "-dn", dn, "-san_dnsname", hostname, "-size 2048 -sig_alg sha256 -eku serverAuth")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -cert -create\": %v %s", ks.command, err, out)
|
return fmt.Errorf("error running \"%v -cert -create\": %v %s", ks.command, err, out)
|
||||||
}
|
}
|
||||||
@@ -145,7 +156,7 @@ func (ks *KeyStore) CreateSelfSignedCertificate(label, dn, hostname string) erro
|
|||||||
|
|
||||||
// Add adds a CA certificate to the keystore
|
// Add adds a CA certificate to the keystore
|
||||||
func (ks *KeyStore) Add(inputFile, label string) error {
|
func (ks *KeyStore) Add(inputFile, label string) error {
|
||||||
out, _, err := command.Run(ks.command, "-cert", "-add", "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile, "-label", label)
|
out, _, err := command.Run(ks.command, "-cert", "-add", ks.getFipsEnabledFlag(), "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile, "-label", label)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
|
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
|
||||||
}
|
}
|
||||||
@@ -154,7 +165,7 @@ func (ks *KeyStore) Add(inputFile, label string) error {
|
|||||||
|
|
||||||
// Add adds a CA certificate to the keystore
|
// Add adds a CA certificate to the keystore
|
||||||
func (ks *KeyStore) AddNoLabel(inputFile string) error {
|
func (ks *KeyStore) AddNoLabel(inputFile string) error {
|
||||||
out, _, err := command.Run(ks.command, "-cert", "-add", "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile)
|
out, _, err := command.Run(ks.command, "-cert", "-add", ks.getFipsEnabledFlag(), "-db", ks.Filename, "-type", ks.keyStoreType, "-pw", ks.Password, "-file", inputFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
|
return fmt.Errorf("error running \"%v -cert -add\": %v %s", ks.command, err, out)
|
||||||
}
|
}
|
||||||
@@ -163,7 +174,7 @@ func (ks *KeyStore) AddNoLabel(inputFile string) error {
|
|||||||
|
|
||||||
// GetCertificateLabels returns the labels of all certificates in the key store
|
// GetCertificateLabels returns the labels of all certificates in the key store
|
||||||
func (ks *KeyStore) GetCertificateLabels() ([]string, error) {
|
func (ks *KeyStore) GetCertificateLabels() ([]string, error) {
|
||||||
out, _, err := command.Run(ks.command, "-cert", "-list", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
|
out, _, err := command.Run(ks.command, "-cert", "-list", ks.getFipsEnabledFlag(), "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
|
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
|
||||||
}
|
}
|
||||||
@@ -207,7 +218,7 @@ func (ks *KeyStore) RenameCertificate(from, to string) error {
|
|||||||
|
|
||||||
// ListAllCertificates Lists all certificates in the keystore
|
// ListAllCertificates Lists all certificates in the keystore
|
||||||
func (ks *KeyStore) ListAllCertificates() ([]string, error) {
|
func (ks *KeyStore) ListAllCertificates() ([]string, error) {
|
||||||
out, _, err := command.Run(ks.command, "-cert", "-list", "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
|
out, _, err := command.Run(ks.command, "-cert", "-list", ks.getFipsEnabledFlag(), "-type", ks.keyStoreType, "-db", ks.Filename, "-pw", ks.Password)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
|
return nil, fmt.Errorf("error running \"%v -cert -list\": %v %s", ks.command, err, out)
|
||||||
}
|
}
|
||||||
@@ -226,3 +237,22 @@ func (ks *KeyStore) ListAllCertificates() ([]string, error) {
|
|||||||
}
|
}
|
||||||
return labels, nil
|
return labels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns the FIPS flag. True if enabled else false
|
||||||
|
func (ks *KeyStore) IsFIPSEnabled() bool {
|
||||||
|
return ks.fipsEnabled
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns -fips option if FIPS is enabled otherwise empty string. Return value is used
|
||||||
|
// when running runmqakm/runmqckm commands.
|
||||||
|
func (ks *KeyStore) getFipsEnabledFlag() string {
|
||||||
|
var fipsEnabled string
|
||||||
|
|
||||||
|
if ks.fipsEnabled {
|
||||||
|
fipsEnabled = "-fips"
|
||||||
|
} else {
|
||||||
|
fipsEnabled = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return fipsEnabled
|
||||||
|
}
|
||||||
|
|||||||
@@ -118,18 +118,25 @@ func ConfigureTLS(keyLabel string, cmsKeystore KeyStoreData, devMode bool, log *
|
|||||||
const mqsc string = "/etc/mqm/15-tls.mqsc"
|
const mqsc string = "/etc/mqm/15-tls.mqsc"
|
||||||
const mqscTemplate string = mqsc + ".tpl"
|
const mqscTemplate string = mqsc + ".tpl"
|
||||||
sslKeyRing := ""
|
sslKeyRing := ""
|
||||||
|
var fipsEnabled = "NO"
|
||||||
|
|
||||||
// Don't set SSLKEYR if no keys or crts are not supplied
|
// Don't set SSLKEYR if no keys or crts are not supplied
|
||||||
// Key label will be blank if no certs were added during processing keys and certs.
|
// Key label will be blank if no private keys were added during processing keys and certs.
|
||||||
if cmsKeystore.Keystore != nil {
|
if cmsKeystore.Keystore != nil && len(keyLabel) > 0 {
|
||||||
certList, _ := cmsKeystore.Keystore.ListAllCertificates()
|
certList, _ := cmsKeystore.Keystore.ListAllCertificates()
|
||||||
if len(certList) > 0 {
|
if len(certList) > 0 {
|
||||||
sslKeyRing = strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb")
|
sslKeyRing = strings.TrimSuffix(cmsKeystore.Keystore.Filename, ".kdb")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cmsKeystore.Keystore.IsFIPSEnabled() {
|
||||||
|
fipsEnabled = "YES"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
|
err := mqtemplate.ProcessTemplateFile(mqscTemplate, mqsc, map[string]string{
|
||||||
"SSLKeyR": sslKeyRing,
|
"SSLKeyR": sslKeyRing,
|
||||||
"CertificateLabel": keyLabel,
|
"CertificateLabel": keyLabel,
|
||||||
|
"SSLFips": fipsEnabled,
|
||||||
}, log)
|
}, log)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -631,7 +638,7 @@ func haveKeysAndCerts(keyDir string) bool {
|
|||||||
// Do a listing of the subdirectory and then search for .key and .cert files
|
// Do a listing of the subdirectory and then search for .key and .cert files
|
||||||
keys, _ := ioutil.ReadDir(filepath.Join(keyDir, fileInfo.Name()))
|
keys, _ := ioutil.ReadDir(filepath.Join(keyDir, fileInfo.Name()))
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
if strings.Contains(key.Name(), ".key") || strings.Contains(key.Name(), ".crt") {
|
if strings.HasSuffix(key.Name(), ".key") || strings.HasSuffix(key.Name(), ".crt") {
|
||||||
// We found at least one key/crt file.
|
// We found at least one key/crt file.
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -77,7 +77,6 @@ func ConfigureWebKeystore(p12Truststore KeyStoreData, webKeystore string) (strin
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return "", fmt.Errorf("Failed to generate certificate in Web Keystore %s with DN of 'CN=%s': %v", webKeystoreFile, genHostName, err)
|
return "", fmt.Errorf("Failed to generate certificate in Web Keystore %s with DN of 'CN=%s': %v", webKeystoreFile, genHostName, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// Check Web Keystore already exists
|
// Check Web Keystore already exists
|
||||||
_, err := os.Stat(webKeystoreFile)
|
_, err := os.Stat(webKeystoreFile)
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
"crypto/tls"
|
||||||
|
|
||||||
"github.com/docker/docker/api/types/container"
|
"github.com/docker/docker/api/types/container"
|
||||||
"github.com/docker/docker/api/types/network"
|
"github.com/docker/docker/api/types/network"
|
||||||
@@ -59,10 +60,10 @@ func TestDevGoldenPath(t *testing.T) {
|
|||||||
runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS, "false", "")
|
runJMSTests(t, cli, id, false, "app", defaultAppPasswordOS, "false", "")
|
||||||
})
|
})
|
||||||
t.Run("REST admin", func(t *testing.T) {
|
t.Run("REST admin", func(t *testing.T) {
|
||||||
testRESTAdmin(t, cli, id, insecureTLSConfig)
|
testRESTAdmin(t, cli, id, insecureTLSConfig, "")
|
||||||
})
|
})
|
||||||
t.Run("REST messaging", func(t *testing.T) {
|
t.Run("REST messaging", func(t *testing.T) {
|
||||||
testRESTMessaging(t, cli, id, insecureTLSConfig, qm, "app", defaultAppPasswordWeb)
|
testRESTMessaging(t, cli, id, insecureTLSConfig, qm, "app", defaultAppPasswordWeb, "")
|
||||||
})
|
})
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, id)
|
stopContainer(t, cli, id)
|
||||||
@@ -124,10 +125,10 @@ func TestDevSecure(t *testing.T) {
|
|||||||
runJMSTests(t, cli, ctr.ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
|
runJMSTests(t, cli, ctr.ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
|
||||||
})
|
})
|
||||||
t.Run("REST admin", func(t *testing.T) {
|
t.Run("REST admin", func(t *testing.T) {
|
||||||
testRESTAdmin(t, cli, ctr.ID, insecureTLSConfig)
|
testRESTAdmin(t, cli, ctr.ID, insecureTLSConfig, "")
|
||||||
})
|
})
|
||||||
t.Run("REST messaging", func(t *testing.T) {
|
t.Run("REST messaging", func(t *testing.T) {
|
||||||
testRESTMessaging(t, cli, ctr.ID, insecureTLSConfig, qm, "app", appPassword)
|
testRESTMessaging(t, cli, ctr.ID, insecureTLSConfig, qm, "app", appPassword, "")
|
||||||
})
|
})
|
||||||
|
|
||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
@@ -343,6 +344,7 @@ func TestSSLKEYRWithCACert(t *testing.T) {
|
|||||||
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
// execute runmqsc to display qmgr SSLKEYR and CERTLABL attibutes.
|
||||||
// Search the console output for exepcted values
|
// Search the console output for exepcted values
|
||||||
_, sslkeyROutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
_, sslkeyROutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL' | runmqsc"})
|
||||||
|
|
||||||
if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
if !strings.Contains(sslkeyROutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
// Although queue manager is ready, it may be that MQSC scripts have not been applied yet.
|
// Although queue manager is ready, it may be that MQSC scripts have not been applied yet.
|
||||||
// Hence wait for a second and retry few times before giving up.
|
// Hence wait for a second and retry few times before giving up.
|
||||||
@@ -371,3 +373,412 @@ func TestSSLKEYRWithCACert(t *testing.T) {
|
|||||||
// Stop the container cleanly
|
// Stop the container cleanly
|
||||||
stopContainer(t, cli, ctr.ID)
|
stopContainer(t, cli, ctr.ID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=false
|
||||||
|
func TestSSLFIPSNO(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=QM1",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
|
"MQ_ENABLE_FIPS=false",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkingConfig := network.NetworkingConfig{}
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanContainer(t, cli, ctr.ID)
|
||||||
|
startContainer(t, cli, ctr.ID)
|
||||||
|
waitForReady(t, cli, ctr.ID)
|
||||||
|
|
||||||
|
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
||||||
|
// Search the console output for exepcted values
|
||||||
|
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
||||||
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
if !strings.Contains(sslFIPSOutput, "CERTLABL(default)") {
|
||||||
|
t.Errorf("Expected CERTLABL to be 'default' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(sslFIPSOutput, "SSLFIPS(NO)") {
|
||||||
|
t.Errorf("Expected SSLFIPS to be 'NO' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies SSLFIPS is set to YES if certificates for queue manager
|
||||||
|
// are supplied and MQ_ENABLE_FIPS=true
|
||||||
|
func TestSSLFIPSYES(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
appPassword := "differentPassw0rd"
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_APP_PASSWORD=" + appPassword,
|
||||||
|
"MQ_QMGR_NAME=QM1",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
|
"MQ_ENABLE_FIPS=true",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkingConfig := network.NetworkingConfig{}
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanContainer(t, cli, ctr.ID)
|
||||||
|
startContainer(t, cli, ctr.ID)
|
||||||
|
waitForReady(t, cli, ctr.ID)
|
||||||
|
|
||||||
|
// Check for expected message on container log
|
||||||
|
logs := inspectLogs(t, cli, ctr.ID)
|
||||||
|
if !strings.Contains(logs, "FIPS cryptography is enabled.") {
|
||||||
|
t.Errorf("Expected 'FIPS cryptography is enabled.' but got %v\n", logs)
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
||||||
|
// Search the console output for exepcted values
|
||||||
|
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
||||||
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
if !strings.Contains(sslFIPSOutput, "CERTLABL(default)") {
|
||||||
|
t.Errorf("Expected CERTLABL to be 'default' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(sslFIPSOutput, "SSLFIPS(YES)") {
|
||||||
|
t.Errorf("Expected SSLFIPS to be 'YES' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run("JMS", func(t *testing.T) {
|
||||||
|
// Run the JMS tests, with no password specified
|
||||||
|
runJMSTests(t, cli, ctr.ID, true, "app", appPassword, "false", "TLS_RSA_WITH_AES_256_CBC_SHA256")
|
||||||
|
})
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestDevSecureFIPSYESWeb verifies if the MQ Web Server is running in FIPS mode
|
||||||
|
func TestDevSecureFIPSTrueWeb(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const tlsPassPhrase string = "passw0rd"
|
||||||
|
qm := "qm1"
|
||||||
|
appPassword := "differentPassw0rd"
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=" + qm,
|
||||||
|
"MQ_APP_PASSWORD=" + appPassword,
|
||||||
|
"DEBUG=1",
|
||||||
|
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
|
||||||
|
"MQ_ENABLE_FIPS=true",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
|
tlsDir(t, false) + ":/etc/mqm/pki/trust/default",
|
||||||
|
},
|
||||||
|
// Assign a random port for the web server on the host
|
||||||
|
// TODO: Don't do this for all tests
|
||||||
|
PortBindings: nat.PortMap{
|
||||||
|
"9443/tcp": []nat.PortBinding{
|
||||||
|
{
|
||||||
|
HostIP: "0.0.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkingConfig := network.NetworkingConfig{}
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanContainer(t, cli, ctr.ID)
|
||||||
|
|
||||||
|
startContainer(t, cli, ctr.ID)
|
||||||
|
waitForReady(t, cli, ctr.ID)
|
||||||
|
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
||||||
|
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
||||||
|
|
||||||
|
// Create a TLS Config with a cipher to use when connecting over HTTPS
|
||||||
|
var secureTLSConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384})
|
||||||
|
// Put a message to queue
|
||||||
|
t.Run("REST messaging", func(t *testing.T) {
|
||||||
|
testRESTMessaging(t, cli, ctr.ID, secureTLSConfig, qm, "app", appPassword, "")
|
||||||
|
})
|
||||||
|
|
||||||
|
// Create a TLS Config with a non-FIPS cipher to use when connecting over HTTPS
|
||||||
|
var secureNonFIPSCipherConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA})
|
||||||
|
// Put a message to queue - the attempt to put message will fail with a EOF return message.
|
||||||
|
t.Run("REST messaging", func(t *testing.T) {
|
||||||
|
testRESTMessaging(t, cli, ctr.ID, secureNonFIPSCipherConfig, qm, "app", appPassword, "EOF")
|
||||||
|
})
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestDevSecureNOFIPSWeb verifies if the MQ Web Server is not running in FIPS mode
|
||||||
|
func TestDevSecureFalseFIPSWeb(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
const tlsPassPhrase string = "passw0rd"
|
||||||
|
qm := "qm1"
|
||||||
|
appPassword := "differentPassw0rd"
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=" + qm,
|
||||||
|
"MQ_APP_PASSWORD=" + appPassword,
|
||||||
|
"DEBUG=1",
|
||||||
|
"WLP_LOGGING_MESSAGE_FORMAT=JSON",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER_LOG=true",
|
||||||
|
"MQ_ENABLE_FIPS=false",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
|
tlsDir(t, false) + ":/etc/mqm/pki/trust/default",
|
||||||
|
},
|
||||||
|
// Assign a random port for the web server on the host
|
||||||
|
PortBindings: nat.PortMap{
|
||||||
|
"9443/tcp": []nat.PortBinding{
|
||||||
|
{
|
||||||
|
HostIP: "0.0.0.0",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkingConfig := network.NetworkingConfig{}
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanContainer(t, cli, ctr.ID)
|
||||||
|
startContainer(t, cli, ctr.ID)
|
||||||
|
waitForReady(t, cli, ctr.ID)
|
||||||
|
|
||||||
|
cert := filepath.Join(tlsDir(t, true), "server.crt")
|
||||||
|
waitForWebReady(t, cli, ctr.ID, createTLSConfig(t, cert, tlsPassPhrase))
|
||||||
|
|
||||||
|
// As FIPS is not enabled, the MQ WebServer (actually Java) will choose a JSSE provider from the list
|
||||||
|
// specified in java.security file. We will need to enable java.net.debug and then parse the web server
|
||||||
|
// logs to check what JJSE provider is being used. Hence just check the jvm.options file does not contain
|
||||||
|
// -Dcom.ibm.jsse2.usefipsprovider line.
|
||||||
|
_, jvmOptionsOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "cat /var/mqm/web/installations/Installation1/servers/mqweb/configDropins/defaults/jvm.options"})
|
||||||
|
if strings.Contains(jvmOptionsOutput, "-Dcom.ibm.jsse2.usefipsprovider") {
|
||||||
|
t.Errorf("Did not expect -Dcom.ibm.jsse2.usefipsprovider but it is not; got \"%v\"", jvmOptionsOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Just do a HTTPS GET as well to query installation details.
|
||||||
|
var secureTLSConfig *tls.Config = createTLSConfigWithCipher(t, cert, tlsPassPhrase, []uint16{tls.TLS_RSA_WITH_AES_256_GCM_SHA384})
|
||||||
|
t.Run("REST admin", func(t *testing.T) {
|
||||||
|
testRESTAdmin(t, cli, ctr.ID, secureTLSConfig, "")
|
||||||
|
})
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify SSLFIPS is set to NO if no certificates were supplied
|
||||||
|
func TestSSLFIPSTrueNoCerts(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
appPassword := "differentPassw0rd"
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_APP_PASSWORD=" + appPassword,
|
||||||
|
"MQ_QMGR_NAME=QM1",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
|
"MQ_ENABLE_FIPS=true",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkingConfig := network.NetworkingConfig{}
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanContainer(t, cli, ctr.ID)
|
||||||
|
startContainer(t, cli, ctr.ID)
|
||||||
|
waitForReady(t, cli, ctr.ID)
|
||||||
|
|
||||||
|
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
||||||
|
// Search the console output for exepcted values
|
||||||
|
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
||||||
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR( )") {
|
||||||
|
t.Errorf("Expected SSLKEYR to be ' ' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
if !strings.Contains(sslFIPSOutput, "CERTLABL( )") {
|
||||||
|
t.Errorf("Expected CERTLABL to be blank but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(sslFIPSOutput, "SSLFIPS(NO)") {
|
||||||
|
t.Errorf("Expected SSLFIPS to be 'NO' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verifies SSLFIPS is set to NO if MQ_ENABLE_FIPS=tru (invalid value)
|
||||||
|
func TestSSLFIPSInvalidValue(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=QM1",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
|
"MQ_ENABLE_FIPS=tru",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
tlsDir(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkingConfig := network.NetworkingConfig{}
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanContainer(t, cli, ctr.ID)
|
||||||
|
startContainer(t, cli, ctr.ID)
|
||||||
|
waitForReady(t, cli, ctr.ID)
|
||||||
|
|
||||||
|
// execute runmqsc to display qmgr SSLKEYR, SSLFIPS and CERTLABL attibutes.
|
||||||
|
// Search the console output for exepcted values
|
||||||
|
_, sslFIPSOutput := execContainer(t, cli, ctr.ID, "", []string{"bash", "-c", "echo 'DISPLAY QMGR SSLKEYR CERTLABL SSLFIPS' | runmqsc"})
|
||||||
|
if !strings.Contains(sslFIPSOutput, "SSLKEYR(/run/runmqserver/tls/key)") {
|
||||||
|
t.Errorf("Expected SSLKEYR to be '/run/runmqserver/tls/key' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(sslFIPSOutput, "CERTLABL(default)") {
|
||||||
|
t.Errorf("Expected CERTLABL to be 'default' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !strings.Contains(sslFIPSOutput, "SSLFIPS(NO)") {
|
||||||
|
t.Errorf("Expected SSLFIPS to be 'NO' but it is not; got \"%v\"", sslFIPSOutput)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Container creation fails when invalid certs are passed and MQ_ENABLE_FIPS set true
|
||||||
|
func TestSSLFIPSBadCerts(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerConfig := container.Config{
|
||||||
|
Env: []string{
|
||||||
|
"LICENSE=accept",
|
||||||
|
"MQ_QMGR_NAME=QM1",
|
||||||
|
"MQ_ENABLE_EMBEDDED_WEB_SERVER=false",
|
||||||
|
"MQ_ENABLE_FIPS=true",
|
||||||
|
},
|
||||||
|
Image: imageName(),
|
||||||
|
}
|
||||||
|
hostConfig := container.HostConfig{
|
||||||
|
Binds: []string{
|
||||||
|
coverageBind(t),
|
||||||
|
tlsDirInvalid(t, false) + ":/etc/mqm/pki/keys/default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
networkingConfig := network.NetworkingConfig{}
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), &containerConfig, &hostConfig, &networkingConfig, t.Name())
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer cleanContainer(t, cli, ctr.ID)
|
||||||
|
startContainer(t, cli, ctr.ID)
|
||||||
|
|
||||||
|
rc := waitForContainer(t, cli, ctr.ID, 20*time.Second)
|
||||||
|
// Expect return code 1 if container failed to create.
|
||||||
|
if rc == 1 {
|
||||||
|
// Get container logs and search for specific message.
|
||||||
|
logs := inspectLogs(t, cli, ctr.ID)
|
||||||
|
if strings.Contains(logs, "Failed to parse private key") {
|
||||||
|
t.Logf("Container creating failed because of invalid certifates")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Some other error occurred.
|
||||||
|
t.Errorf("Expected rc=0, got rc=%v", rc)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop the container cleanly
|
||||||
|
stopContainer(t, cli, ctr.ID)
|
||||||
|
}
|
||||||
|
|||||||
@@ -86,6 +86,10 @@ func tlsDirWithCA(t *testing.T, unixPath bool) string {
|
|||||||
return filepath.Join(getCwd(t, unixPath), "../tlscacert")
|
return filepath.Join(getCwd(t, unixPath), "../tlscacert")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func tlsDirInvalid(t *testing.T, unixPath bool) string {
|
||||||
|
return filepath.Join(getCwd(t, unixPath), "../tlsinvalidcert")
|
||||||
|
}
|
||||||
|
|
||||||
// runJMSTests runs a container with a JMS client, which connects to the queue manager container with the specified ID
|
// runJMSTests runs a container with a JMS client, which connects to the queue manager container with the specified ID
|
||||||
func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string, ibmjre string, cipherName string) {
|
func runJMSTests(t *testing.T, cli *client.Client, ID string, tls bool, user, password string, ibmjre string, cipherName string) {
|
||||||
containerConfig := container.Config{
|
containerConfig := container.Config{
|
||||||
@@ -201,7 +205,7 @@ func createTLSConfig(t *testing.T, certFile, password string) *tls.Config {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRESTAdmin(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config) {
|
func testRESTAdmin(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config, errorExpected string) {
|
||||||
httpClient := http.Client{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(30 * time.Second),
|
Timeout: time.Duration(30 * time.Second),
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
@@ -213,9 +217,15 @@ func testRESTAdmin(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.C
|
|||||||
req.SetBasicAuth("admin", defaultAdminPassword)
|
req.SetBasicAuth("admin", defaultAdminPassword)
|
||||||
resp, err := httpClient.Do(req)
|
resp, err := httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if len(errorExpected) > 0 {
|
||||||
|
if !strings.Contains(err.Error(), errorExpected) {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if resp.StatusCode != http.StatusOK {
|
} else {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if resp != nil && resp.StatusCode != http.StatusOK {
|
||||||
t.Errorf("Expected HTTP status code %v from 'GET installation'; got %v", http.StatusOK, resp.StatusCode)
|
t.Errorf("Expected HTTP status code %v from 'GET installation'; got %v", http.StatusOK, resp.StatusCode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -238,7 +248,7 @@ func logHTTPResponse(t *testing.T, resp *http.Response) {
|
|||||||
t.Logf("HTTP response: %v", string(d))
|
t.Logf("HTTP response: %v", string(d))
|
||||||
}
|
}
|
||||||
|
|
||||||
func testRESTMessaging(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config, qmName string, user string, password string) {
|
func testRESTMessaging(t *testing.T, cli *client.Client, ID string, tlsConfig *tls.Config, qmName string, user string, password string, errorExpected string) {
|
||||||
httpClient := http.Client{
|
httpClient := http.Client{
|
||||||
Timeout: time.Duration(30 * time.Second),
|
Timeout: time.Duration(30 * time.Second),
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
@@ -255,10 +265,19 @@ func testRESTMessaging(t *testing.T, cli *client.Client, ID string, tlsConfig *t
|
|||||||
logHTTPRequest(t, req)
|
logHTTPRequest(t, req)
|
||||||
resp, err := httpClient.Do(req)
|
resp, err := httpClient.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if len(errorExpected) > 0 {
|
||||||
|
if strings.Contains(err.Error(), errorExpected) {
|
||||||
|
t.Logf("Error contains expected '%s' value", errorExpected)
|
||||||
|
return
|
||||||
|
} else {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
logHTTPResponse(t, resp)
|
logHTTPResponse(t, resp)
|
||||||
if resp.StatusCode != http.StatusCreated {
|
if resp != nil && resp.StatusCode != http.StatusCreated {
|
||||||
t.Errorf("Expected HTTP status code %v from 'POST to queue'; got %v", http.StatusOK, resp.StatusCode)
|
t.Errorf("Expected HTTP status code %v from 'POST to queue'; got %v", http.StatusOK, resp.StatusCode)
|
||||||
t.Logf("HTTP response: %+v", resp)
|
t.Logf("HTTP response: %+v", resp)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -286,3 +305,28 @@ func testRESTMessaging(t *testing.T, cli *client.Client, ID string, tlsConfig *t
|
|||||||
t.Errorf("Expected payload to be \"%s\"; got \"%s\"", putMessage, gotMessage)
|
t.Errorf("Expected payload to be \"%s\"; got \"%s\"", putMessage, gotMessage)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// createTLSConfig creates a tls.Config which trusts the specified certificate
|
||||||
|
func createTLSConfigWithCipher(t *testing.T, certFile, password string, ciphers []uint16) *tls.Config {
|
||||||
|
// Get the SystemCertPool, continue with an empty pool on error
|
||||||
|
certs, err := x509.SystemCertPool()
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Read in the cert file
|
||||||
|
cert, err := ioutil.ReadFile(certFile)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
// Append our cert to the system pool
|
||||||
|
ok := certs.AppendCertsFromPEM(cert)
|
||||||
|
if !ok {
|
||||||
|
t.Fatal("No certs appended")
|
||||||
|
}
|
||||||
|
// Trust the augmented cert pool in our client
|
||||||
|
return &tls.Config{
|
||||||
|
InsecureSkipVerify: false,
|
||||||
|
RootCAs: certs,
|
||||||
|
CipherSuites: ciphers,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -134,7 +134,6 @@ func goldenPath(t *testing.T, metric bool) {
|
|||||||
stopContainer(t, cli, id)
|
stopContainer(t, cli, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName string) {
|
func utilTestNoQueueManagerName(t *testing.T, hostName string, expectedName string) {
|
||||||
search := "QMNAME(" + expectedName + ")"
|
search := "QMNAME(" + expectedName + ")"
|
||||||
cli, err := client.NewClientWithOpts(client.FromEnv)
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
|||||||
@@ -889,3 +889,42 @@ func getMQVersion(t *testing.T, cli *client.Client) (string, error) {
|
|||||||
version := inspect.ContainerConfig.Labels["version"]
|
version := inspect.ContainerConfig.Labels["version"]
|
||||||
return version, nil
|
return version, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// runContainerWithAllConfig creates and starts a container, using the supplied ContainerConfig, HostConfig,
|
||||||
|
// NetworkingConfig, and container name (or the value of t.Name if containerName="").
|
||||||
|
func runContainerWithAllConfigError(t *testing.T, cli *client.Client, containerConfig *container.Config, hostConfig *container.HostConfig, networkingConfig *network.NetworkingConfig, containerName string) (string, error) {
|
||||||
|
if containerName == "" {
|
||||||
|
containerName = t.Name()
|
||||||
|
}
|
||||||
|
if containerConfig.Image == "" {
|
||||||
|
containerConfig.Image = imageName()
|
||||||
|
}
|
||||||
|
// Always run as a random user, unless the test has specified otherwise
|
||||||
|
if containerConfig.User == "" {
|
||||||
|
containerConfig.User = generateRandomUID()
|
||||||
|
}
|
||||||
|
// if coverage
|
||||||
|
containerConfig.Env = append(containerConfig.Env, "COVERAGE_FILE="+t.Name()+".cov")
|
||||||
|
containerConfig.Env = append(containerConfig.Env, "EXIT_CODE_FILE="+getExitCodeFilename(t))
|
||||||
|
t.Logf("Running container (%s)", containerConfig.Image)
|
||||||
|
ctr, err := cli.ContainerCreate(context.Background(), containerConfig, hostConfig, networkingConfig, containerName)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
err = startContainerError(t, cli, ctr.ID)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return ctr.ID, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func startContainerError(t *testing.T, cli *client.Client, ID string) error {
|
||||||
|
t.Logf("Starting container: %v", ID)
|
||||||
|
startOptions := types.ContainerStartOptions{}
|
||||||
|
err := cli.ContainerStart(context.Background(), ID, startOptions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,9 +16,9 @@ limitations under the License.
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"testing"
|
|
||||||
|
|
||||||
"github.com/docker/docker/client"
|
"github.com/docker/docker/client"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestNativeHABasic creates 3 containers in a Native HA queue manager configuration
|
// TestNativeHABasic creates 3 containers in a Native HA queue manager configuration
|
||||||
@@ -217,3 +217,96 @@ func TestNativeHASecureCipherSpec(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
|
||||||
|
// with HA TLS FIPS enabled, overrides the default CipherSpec, and ensures the queue manger
|
||||||
|
// and replicas start as expected. This test uses FIPS compliant cipher.
|
||||||
|
func TestNativeHASecureCipherSpecFIPS(t *testing.T) {
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := getMQVersion(t, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if version < "9.2.2.0" {
|
||||||
|
t.Skipf("Skipping %s as test requires at least MQ 9.2.2.0, but image is version %s", t.Name(), version)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
|
qmReplicaIDs := [3]string{}
|
||||||
|
qmNetwork, err := createBridgeNetwork(cli, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
||||||
|
|
||||||
|
for i := 0; i <= 2; i++ {
|
||||||
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
|
// MQ_NATIVE_HA_CIPHERSPEC is set a FIPS compliant cipherspec.
|
||||||
|
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true", "MQ_NATIVE_HA_CIPHERSPEC=TLS_RSA_WITH_AES_128_GCM_SHA256", "MQ_ENABLE_FIPS=true")
|
||||||
|
hostConfig := getNativeHASecureHostConfig(t)
|
||||||
|
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
||||||
|
|
||||||
|
ctr := runContainerWithAllConfig(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
|
defer cleanContainer(t, cli, ctr)
|
||||||
|
qmReplicaIDs[i] = ctr
|
||||||
|
}
|
||||||
|
|
||||||
|
waitForReadyHA(t, cli, qmReplicaIDs)
|
||||||
|
// Display the contents of qm.ini
|
||||||
|
_, qmini := execContainer(t, cli, qmReplicaIDs[0], "", []string{"cat", "/var/mqm/qmgrs/QM1/qm.ini"})
|
||||||
|
if !strings.Contains(qmini, "SSLFipsRequired=Yes") {
|
||||||
|
t.Errorf("Expected SSLFipsRequired=Yes but it is not; got \"%v\"", qmini)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = getActiveReplicaInstances(t, cli, qmReplicaIDs)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestNativeHASecure creates 3 containers in a Native HA queue manager configuration
|
||||||
|
// with HA TLS FIPS enabled with non-FIPS cipher, overrides the default CipherSpec, and
|
||||||
|
// ensures the queue manger and replicas don't start as expected
|
||||||
|
func TestNativeHASecureCipherSpecNonFIPSCipher(t *testing.T) {
|
||||||
|
cli, err := client.NewClientWithOpts(client.FromEnv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
version, err := getMQVersion(t, cli)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
if version < "9.2.2.0" {
|
||||||
|
t.Skipf("Skipping %s as test requires at least MQ 9.2.2.0, but image is version %s", t.Name(), version)
|
||||||
|
}
|
||||||
|
|
||||||
|
containerNames := [3]string{"QM1_1", "QM1_2", "QM1_3"}
|
||||||
|
qmReplicaIDs := [3]string{}
|
||||||
|
qmNetwork, err := createBridgeNetwork(cli, t)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer removeBridgeNetwork(cli, qmNetwork.ID)
|
||||||
|
|
||||||
|
for i := 0; i <= 2; i++ {
|
||||||
|
containerConfig := getNativeHAContainerConfig(containerNames[i], containerNames, defaultHAPort)
|
||||||
|
// MQ_NATIVE_HA_CIPHERSPEC is set a FIPS non-compliant cipherspec - SSL_ECDHE_ECDSA_WITH_RC4_128_SHA
|
||||||
|
containerConfig.Env = append(containerConfig.Env, "MQ_NATIVE_HA_TLS=true", "MQ_NATIVE_HA_CIPHERSPEC=TLS_RSA_WITH_AES_128_GCM_SHA256", "MQ_ENABLE_FIPS=true")
|
||||||
|
hostConfig := getNativeHASecureHostConfig(t)
|
||||||
|
networkingConfig := getNativeHANetworkConfig(qmNetwork.ID)
|
||||||
|
|
||||||
|
ctr, err := runContainerWithAllConfigError(t, cli, &containerConfig, &hostConfig, &networkingConfig, containerNames[i])
|
||||||
|
defer cleanContainer(t, cli, ctr)
|
||||||
|
// We expect container to fail in this case because the cipher is non-FIPS and we have asked for FIPS compliance
|
||||||
|
// by setting MQ_ENABLE_FIPS=true
|
||||||
|
if err == nil {
|
||||||
|
t.Logf("Container start expected to fail but did not. %v", err)
|
||||||
|
}
|
||||||
|
qmReplicaIDs[i] = ctr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -106,7 +106,7 @@ func getActiveReplicaInstances(t *testing.T, cli *client.Client, qmReplicaIDs [3
|
|||||||
|
|
||||||
func waitForReadyHA(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) {
|
func waitForReadyHA(t *testing.T, cli *client.Client, qmReplicaIDs [3]string) {
|
||||||
|
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Minute)
|
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Minute)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
|||||||
30
test/tlsinvalidcert/expired.key
Normal file
30
test/tlsinvalidcert/expired.key
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
-----BEGIN ENCRYPTED PRIVATE KEY-----
|
||||||
|
MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIxuHuzG+WcZACAggA
|
||||||
|
MBQGCCqGSIb3DQMHBAgMKyhajZd/ewSCBMiCL57/BUvVwtxmhaIqQBSjHLnx+AvG
|
||||||
|
f+frFkwM52KuAg0Q+vF/1iQXMbZRrHpxNz/1t3cIdwzlc9S3FB+L42q0CEH0c1FW
|
||||||
|
6gB6csmb1AyhGYffwkeT8bPkELJhpO2taIFTynwDhHaeKeDce3EwQ5xQd4ydq1Ku
|
||||||
|
t4oJZun51J5qvNs91BiHHVB3/q1Lnh4VK4TTDgXTGfu8qcuOexHQcOgko4oemorv
|
||||||
|
E1Woy6Lf99bePxedSuMIxPAXysSCBqcrZDbY9K3yaxV6Gr7S9FBVvOx9r8PTaFEY
|
||||||
|
sXxdtB22qM1PqZIIjK6nzwXb5iu8wcaZFatD6y7RQaS0kz5EcS5kExrEocFV7D1T
|
||||||
|
dtTf6tt31PbtKfEauRjz3fBXMw+r3Pu/hWRXd3og9hfzFQz49v9RdvgkHy57uCY+
|
||||||
|
F/fN3BKyTcTqJWKpBDMx/xtD1kXWHf81SFmckuShbgKjDvZraR4RmzO/9upIDCFF
|
||||||
|
rJ85takmPvZyAdfvZp6RqVja+cphI4nmxVvmOmUiFMmUJ0lv9MhqpxdVFfleWz0w
|
||||||
|
9XxeL4l+cd/Kbl2ihHwF4oOzWlamyRZjoWiq5s/ika9I1iQ40rGTThqnphonlhUz
|
||||||
|
HX4NvA+fbugwqyOjqEkg5AqyP5ucUN3Hl0qd7wqAJprDkB938unKo/1sr82PfdO/
|
||||||
|
5UvzsKz2ieVavEzi/NxYyR+Xjm3YHG1akcftvElcpYepvemt/PtXJH8fX29b1X6C
|
||||||
|
TYxV03MeA1sJXeM9iqIf/wGQJ657U5ciXUyUtU8s0dDY+jqpZVjxekgCove9FNXz
|
||||||
|
Mja15yiAy/F8xKX20ZRisg+Ly60UQYbX6Wu6Uy6NMjWkxZOYebCVYLMag6UjS0CS
|
||||||
|
8n3/DNvuVooGWbgBFs0tyabtlz/Fz5jGktkMBQeEK4PZKZdMt9aXnDfPFGJWrsme
|
||||||
|
bUzEZLZSWD2Zwr/ujzfBgVeg56AyHJzHuOOLaofZ90ecv69Udl7sYZBelFXxgN8R
|
||||||
|
JVXyV0kNZYj9LaqRTi54H8YToAIV7GXIcasH3jP54dOba3px2NXbaiMf7Oe8apyW
|
||||||
|
E7/vKQNoIbWaglRHXVPGoATTUzYNdBO4jca1rTOXjmzsiZl1JGPwQsS03PuTfa8C
|
||||||
|
F7Uqxj8P9m71G1KuLYA1es55aNXzXSx6uqrRYeu0iug/jE+voGfjbRW3BUY/qxtl
|
||||||
|
OjR8pCDPLN6/rt//ejvBdA4gPDgjRNH4fO9DULQDqIVHmYlysZqhbPbhzmiBXZVP
|
||||||
|
zw1/z9amWR00OeN7xUvm9n+65dosoIn2v1dOz8JBh6Uooj63D2cOghBwEXoPg53B
|
||||||
|
3vLgqy3NKyNZQ/gGfBjXTTeoWzAy8U8hKecNKcsTBquBeBUfS55WwkbD7Mz0Deho
|
||||||
|
EcMZPZUwAPyJ2kHL74etpoBXuH7Jzo8SVedhE+C5J6F+oUP/JcoXdehdGLI89CHU
|
||||||
|
cUARt91OiF3WQo51xT21GlGL8RMHVpjTnYZinnQ/fE1y7JfWtYshBya+YLlAk5vb
|
||||||
|
9jt0tZ9I/KhJ579ZwWBH8V179kBr5Vn+uWlEBBaJu0abdbRSDjt6fAaxi3Q8XK+c
|
||||||
|
isuVuzN/8JAeRgRpm7hRfIoG6XOsrY72ktz0JiHflZ+90xaPRvpCA9/mFC5qp1zh
|
||||||
|
yBs=
|
||||||
|
-----END ENCRYPTED PRIVATE KEY-----
|
||||||
BIN
test/tlsinvalidcert/expired.p12
Normal file
BIN
test/tlsinvalidcert/expired.p12
Normal file
Binary file not shown.
26
test/tlsinvalidcert/expired.pem
Normal file
26
test/tlsinvalidcert/expired.pem
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIEaTCCAlECAQEwDQYJKoZIhvcNAQEFBQAwgZ8xCzAJBgNVBAYTAlVTMREwDwYD
|
||||||
|
VQQIDAhOZXcgWW9yazEPMA0GA1UEBwwGQXJtb25rMTQwMgYDVQQKDCtJbnRlcm5h
|
||||||
|
dGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0aW9uMTYwNAYDVQQDDC1N
|
||||||
|
USBMaWdodCBFeHBpcmVkIENBIChmb3IgZXhwaXJlZCBzaWduZWQgY2VydCkwHhcN
|
||||||
|
MTUwMzI4MTMwNDI2WhcNMTUwMzI5MTMwNDI2WjBVMQswCQYDVQQGEwJHQjESMBAG
|
||||||
|
A1UECAwJSGFtcHNoaXJlMRAwDgYDVQQHDAdIdXJzbGV5MQwwCgYDVQQKDANJQk0x
|
||||||
|
EjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
|
||||||
|
ggEBAMeNfSaC0XZoi9CHXLUHz7BA8frIlz+gnl1sjaGimsofiMjd8a0c4pOhlusR
|
||||||
|
kvB4qAQDxmDYhh9QTuqiJZvQxzTI3sNt4W3kcm/bEVawg8HvsWBY40fKkWJYlypV
|
||||||
|
K4Oizcri7CLaeUwgpJlrSlYiJSzjaaytTDeC1F+RSTrdDg0CxI+pfhxIkc9+HPMC
|
||||||
|
oSv1ynxktcJPnCLGRIIHYCE4jm1ZsYxAkSV1crja5OQdd3czEMz6wfHdYzTJUEa1
|
||||||
|
pmnTOa9lhuxlYb8ykt7G2CK66tXaoN0SsAsy6sT2SblI16RDkyOL5XJk56ThhHrn
|
||||||
|
XjjWr3Zo4/tE/pgn5fd+91oi2+ECAwEAATANBgkqhkiG9w0BAQUFAAOCAgEAZNZn
|
||||||
|
OJVQ54NLCzCyTiTauG2jJU+3aYEG4hRhpLM6N11vrukIFTeVfbrr1uKp7sLHYB0E
|
||||||
|
6xLgTxhKF2lDHzCPjA3bOO0tDsxwkOZNP//jmMi+9VKd6Voh/UENOVnBHaXLb5G2
|
||||||
|
9OXi70W/K8eQU7Qi+tu+snWNLYHb5nsYKnPed3+h/zLV3iNB7cz2DCNCas2cKekx
|
||||||
|
6hJo+tWoC+jXcpM97pnqY6saYNmKmugIdZ1W77jueoEIIkSMAZvd8sgXzE6Ad8mD
|
||||||
|
bTMimX9ri0APgxZewaF51YzR2yKqgkpvLVBef0nCbjCDK5zgJVSQHtVJswE4mIcL
|
||||||
|
J3PbSxtmt3BcIr9jmYZZjmoXSjK0+YQkDYT9/uiE5h+6KXrk4AOTkcO9kuxQcBAD
|
||||||
|
QYJB8Hr7h9OcWmpOOJDjOz4BspBwQ7Vs2swHBQgWu9mS9I187JFSFm46dp9CnqSV
|
||||||
|
K5i5amsrJUcRtqlBs4JzqsLivUaet+BtQwlWDfl52TgWpWeIs2EiPFERZxiEggVr
|
||||||
|
pIhjZ9F2d0pL1Oj5jCWMRGWrz1px5W4r92uzfYvTrT/eyGNGGNdDeAgidJ4SftXu
|
||||||
|
XMcqgVjAy0kKvQEK9bCqfoOxTllFqLcneaPI6O0hLREph6sti6eDvJeMsUGoYm/7
|
||||||
|
MxfCaqBU1HStl0HHPaaqHnPP+FW+/xuXhHij1hY=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
BIN
test/tlsinvalidcert/expiredCA.p12
Normal file
BIN
test/tlsinvalidcert/expiredCA.p12
Normal file
Binary file not shown.
35
test/tlsinvalidcert/expiredCA.pem
Normal file
35
test/tlsinvalidcert/expiredCA.pem
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIGEzCCA/ugAwIBAgIJAI+sAC+/ups4MA0GCSqGSIb3DQEBBQUAMIGfMQswCQYD
|
||||||
|
VQQGEwJVUzERMA8GA1UECAwITmV3IFlvcmsxDzANBgNVBAcMBkFybW9uazE0MDIG
|
||||||
|
A1UECgwrSW50ZXJuYXRpb25hbCBCdXNpbmVzcyBNYWNoaW5lcyBDb3Jwb3JhdGlv
|
||||||
|
bjE2MDQGA1UEAwwtTVEgTGlnaHQgRXhwaXJlZCBDQSAoZm9yIGV4cGlyZWQgc2ln
|
||||||
|
bmVkIGNlcnQpMB4XDTE1MDQwMTExNTkxNloXDTQyMDgxNjExNTkxNlowgZ8xCzAJ
|
||||||
|
BgNVBAYTAlVTMREwDwYDVQQIDAhOZXcgWW9yazEPMA0GA1UEBwwGQXJtb25rMTQw
|
||||||
|
MgYDVQQKDCtJbnRlcm5hdGlvbmFsIEJ1c2luZXNzIE1hY2hpbmVzIENvcnBvcmF0
|
||||||
|
aW9uMTYwNAYDVQQDDC1NUSBMaWdodCBFeHBpcmVkIENBIChmb3IgZXhwaXJlZCBz
|
||||||
|
aWduZWQgY2VydCkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDLGn4P
|
||||||
|
97BZteNO/5zIlGH4F067TPlOjFiLI1TFI/bKp3bx1fHpsQdMX5C9y1s6BqoOzMJV
|
||||||
|
VHDJH4NlxvnMUGNzYvluynjujejhyDryDrb4uY3JMcewvnHmrWArzbfZw4eBzANr
|
||||||
|
feBkro4xr6m5HWMxM4GJZeFaEGqbXNE5vAYhZ270qUKqrkSHv4g/LqapITaBPJDC
|
||||||
|
3tAtV0UD4/HmwB2ogZlXy4DkbBsgcc2rS4xPxx3Qki78DeA9oT6aeLP7KZnoEgo9
|
||||||
|
Xqb/UfRuZ5MYR17u8yTuJz/JdAs6Saf80t5PLDO/SRKj7Uu1lt+HbkpEghdEdB/V
|
||||||
|
pPdmlIfo7uNe7rFG/OWif2qwVm2t9o02oIUqlAHggS4WYeOmcB8L9EtmlfZHaoDA
|
||||||
|
H0a0xlbZ+XlE/EMpphgrzSE5g9h9Vw7vvH5Ygzks8lSXKd5VS8C9y8tWqaMCynAy
|
||||||
|
5MTIZdXMvouG8vy5Ip+iWck4QSo6eJBryLNt/vzljxo6XntveXRZVvywyjh3NuVu
|
||||||
|
nVLPe0CFkmRHXK5/zA6H8rZeGb3eK8Y4VcLKj7x4Lnluo47BeGnKH7UcKBA2AREC
|
||||||
|
VGFVsHcr0HwKgCCSsyv4qRefY/mJWO59BL38shHuzydLxlKHf/uPGdsZ3DU0rb6i
|
||||||
|
QXMCHC6lzAjJHVCDJ2witiPSjmW2LRZzRqdTqwIDAQABo1AwTjAdBgNVHQ4EFgQU
|
||||||
|
dv3XdSdsOkZJDWgusfuZqBx/jpMwHwYDVR0jBBgwFoAUdv3XdSdsOkZJDWgusfuZ
|
||||||
|
qBx/jpMwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAgEAR9o32FR4AjTZ
|
||||||
|
LV5nH5rsQ9OVon1TCv9yemAI4coh08RHWVf7cDyIp8XKy3gTM/lq70wzsXUHwaAS
|
||||||
|
4xSOjc/fBLP0UTEwCrdyy1guRs9ZjKIhqth1AkB92sF9HV4P811vUNppVfA/BDmb
|
||||||
|
Ttl6i1Joyl6nhnDxn1HzjcSBB4ZVt/1MRwIaEfRXrqAklYbMOtw8D6Onth6IQ7dS
|
||||||
|
27ulUPD+AA8H5Ilm2XhPI6ttnR+822+mgB1K9WAjmuIbDJwQJl32UmTUiXPwdlWm
|
||||||
|
KqyKZGST8wV6Jylha84ETL99IlJsxoAMGmNshMe4t773n0LousAvnbVt9uZcBNUH
|
||||||
|
d/53EWP7kw1PPhY6jo0gLVK/ZQt8MHBJuT3f5IM9dmkLJmyM9t8tEmvjNEoC2xSW
|
||||||
|
JHxoWfbMOxxFx+S5CwwcvySpKltio7s5bf/dYexE+Dv/+zMDeMb8GXv811TCqsD2
|
||||||
|
lm4kTsHjwd+zSGCuvH+R4vWbkSrd65CATmFsVpVPLsIVXDa3DrgFQBmUI/q9UFaG
|
||||||
|
K25HztaHk8GJkBZdBA7xXxzSJxW37yqPGKqQ/ZoqSz6XFnsgy5AsW0fDM+cPUl7l
|
||||||
|
tftOlLeSqkaBq9O++76yY2asb0AyqjNs0tajluzxGFZ38DOqA1xkltV/c+KYnEv3
|
||||||
|
q+K4agMHIKMr7lGJfSBevz3mG+NJ7AU=
|
||||||
|
-----END CERTIFICATE-----
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
-Djava.util.prefs.userRoot=/tmp
|
||||||
|
-Djava.util.prefs.systemRoot=/tmp
|
||||||
|
-Dcom.ibm.jsse2.usefipsprovider={{.FipsProvider}}
|
||||||
|
-Dcom.ibm.jsse2.usefipsProviderName={{.FipsProviderName}}
|
||||||
|
|
||||||
Reference in New Issue
Block a user