From 5d7c051c7e9154b3eabf03d37fe28b218d16b177 Mon Sep 17 00:00:00 2001 From: David Quigley Date: Tue, 24 Nov 2020 10:35:32 -0700 Subject: [PATCH] DAOSSDE-112 security: Modifications to use of Cryptography (#3923) After peer review the following modifications were requested: * Remove cipher suite AES128-GCM-SHA256 and just offer AES256-GCM-SHA384 as default. * Reduce certificates to one year lifetime (currently three years) * Replace PKCS #1 v1.2 with PKCS #1 v2.1/2 if possible. The golang core library is being used and may not support it yet. Team to verify if it does and, if so, will try to update. * Add to documentation recommending to customer to use the latest version of OpenSSL >= 1.1.1h. For this project, the customer is responsible for generating keys/certs. * Reduce key sizes to 3072 based on expected lifetime of this product Signed-off-by: David Quigley --- doc/admin/deployment.md | 11 +++++++---- src/control/security/grpc_cert_configs.go | 2 -- .../security/grpc_cert_configs_pre1.15.go | 2 -- src/control/security/signature.go | 4 ++-- src/control/security/signature_test.go | 17 +++++++++++++---- src/control/security/testdata/certs/RSA.golden | Bin 512 -> 512 bytes utils/certs/gen_certificates.sh | 12 ++++++------ 7 files changed, 28 insertions(+), 20 deletions(-) diff --git a/doc/admin/deployment.md b/doc/admin/deployment.md index 2471ace85e1..5d5021e24c4 100644 --- a/doc/admin/deployment.md +++ b/doc/admin/deployment.md @@ -143,7 +143,10 @@ The DAOS security framework relies on certificates to authenticate components and administrators in addition to encrypting DAOS control plane communications. A set of certificates for a given DAOS system may be generated by running the `gen_certificates.sh` script provided with the DAOS -software if there is not an existing TLS certificate infrastructure. +software if there is not an existing TLS certificate infrastructure. The +`gen_certificates.sh` script uses the `openssl` tool to generate all of the +necessary files. We highly recommend using OpenSSL Version 1.1.1h or higher as +keys and certificates generated with earlier versions are vulnerable to attack. When DAOS is installed from RPMs, this script is provided in the base `daos` RPM, and may be invoked in the directory to which the certificates will be written. As part @@ -312,14 +315,14 @@ $ journalctl --unit daos_server.service ``` After RPM install, `daos_server` service starts automatically running as user -"daos". The server config is read from `/etc/daos/daos_server.yml` and +"daos". The server config is read from `/etc/daos/daos_server.yml` and certificates are read from `/etc/daos/certs`. With no other admin intervention other than the loading of certificates, `daos_server` will enter a listening state enabling discovery of storage and network hardware through the `dmg` tool without any I/O Servers specified in the configuration file. After device discovery and provisioning, an updated configuration file with a populated per-server section can be stored in -`/etc/daos/daos_server.yml`, and after reestarting the `daos_server` service +`/etc/daos/daos_server.yml`, and after reestarting the `daos_server` service it is then ready for the storage to be formatted. #### Kubernetes Pod @@ -944,7 +947,7 @@ $ daos_agent -i -o <'path to agent configuration file/daos_agent.yml'> & ``` Alternatively, the DAOS Agent can be started as a systemd service. The DAOS Agent -unit file is installed in the correct location when installing from RPMs. +unit file is installed in the correct location when installing from RPMs. If you want to run the DAOS Agent without certificates (not recommended in production deployments), you need to add the `-i` option to the systemd `ExecStart` invocation (see below). diff --git a/src/control/security/grpc_cert_configs.go b/src/control/security/grpc_cert_configs.go index 6f35e5d4f75..767fe84cc52 100644 --- a/src/control/security/grpc_cert_configs.go +++ b/src/control/security/grpc_cert_configs.go @@ -53,7 +53,6 @@ func serverTLSConfig(cfg *TransportConfig) *tls.Config { MaxVersion: tls.VersionTLS12, PreferServerCipherSuites: true, CipherSuites: []uint16{ - tls.TLS_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_RSA_WITH_AES_256_GCM_SHA384, }, VerifyConnection: func(cs tls.ConnectionState) error { @@ -81,7 +80,6 @@ func clientTLSConfig(cfg *TransportConfig) *tls.Config { MaxVersion: tls.VersionTLS12, PreferServerCipherSuites: true, CipherSuites: []uint16{ - tls.TLS_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_RSA_WITH_AES_256_GCM_SHA384, }, // InsecureSkipVerify disables the default verifier and instead diff --git a/src/control/security/grpc_cert_configs_pre1.15.go b/src/control/security/grpc_cert_configs_pre1.15.go index 09e077ddde7..ed04e54d0f1 100644 --- a/src/control/security/grpc_cert_configs_pre1.15.go +++ b/src/control/security/grpc_cert_configs_pre1.15.go @@ -36,7 +36,6 @@ func serverTLSConfig(cfg *TransportConfig) *tls.Config { MaxVersion: tls.VersionTLS12, PreferServerCipherSuites: true, CipherSuites: []uint16{ - tls.TLS_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_RSA_WITH_AES_256_GCM_SHA384, }, } @@ -51,7 +50,6 @@ func clientTLSConfig(cfg *TransportConfig) *tls.Config { MaxVersion: tls.VersionTLS12, PreferServerCipherSuites: true, CipherSuites: []uint16{ - tls.TLS_RSA_WITH_AES_128_GCM_SHA256, tls.TLS_RSA_WITH_AES_256_GCM_SHA384, }, } diff --git a/src/control/security/signature.go b/src/control/security/signature.go index c96728dcd56..0ca31f49e2c 100644 --- a/src/control/security/signature.go +++ b/src/control/security/signature.go @@ -78,7 +78,7 @@ func (s *TokenSigner) Sign(key crypto.PrivateKey, data []byte) ([]byte, error) { switch signingKey := key.(type) { // TODO: Support key types other than RSA case *rsa.PrivateKey: - return rsa.SignPKCS1v15(s.randPool, signingKey, crypto.SHA512, digest) + return rsa.SignPSS(s.randPool, signingKey, crypto.SHA512, digest, nil) default: return nil, &UnsupportedKeyError{} } @@ -95,7 +95,7 @@ func (s *TokenSigner) Verify(key crypto.PublicKey, data []byte, sig []byte) erro switch signingKey := key.(type) { // TODO: Support key types other than RSA case *rsa.PublicKey: - return rsa.VerifyPKCS1v15(signingKey, crypto.SHA512, digest, sig) + return rsa.VerifyPSS(signingKey, crypto.SHA512, digest, sig, nil) default: return &UnsupportedKeyError{} } diff --git a/src/control/security/signature_test.go b/src/control/security/signature_test.go index c1efb44206c..74f43e5c18e 100644 --- a/src/control/security/signature_test.go +++ b/src/control/security/signature_test.go @@ -28,10 +28,11 @@ import ( "crypto" "crypto/ecdsa" "crypto/elliptic" - "crypto/rand" + crand "crypto/rand" "encoding/hex" "flag" "io/ioutil" + mrand "math/rand" "os" "path/filepath" "testing" @@ -39,6 +40,14 @@ import ( var update = flag.Bool("update", false, "update .golden files") +func SeededSigner() *TokenSigner { + //This should ensure we get the same signature every time for testing purposes. + r := mrand.New(mrand.NewSource(1)) + return &TokenSigner{ + randPool: r, + } +} + func SignTestSetup(t *testing.T) (rsaKey, ecdsaKey crypto.PrivateKey, source []byte) { keyPath := "testdata/certs/daosCA.key" if err := os.Chmod(keyPath, MaxKeyPerm); err != nil { @@ -48,7 +57,7 @@ func SignTestSetup(t *testing.T) (rsaKey, ecdsaKey crypto.PrivateKey, source []b if err != nil { t.Fatalf("Unable to load private key for %s: %s", keyPath, err.Error()) } - ecdsaKey, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + ecdsaKey, err = ecdsa.GenerateKey(elliptic.P256(), crand.Reader) if err != nil { t.Fatal("Failed to generate ecdsa key for testing") } @@ -62,7 +71,7 @@ func SignTestSetup(t *testing.T) (rsaKey, ecdsaKey crypto.PrivateKey, source []b func TestSign(t *testing.T) { rsaKey, ecdsaKey, source := SignTestSetup(t) - tokenSigner := DefaultTokenSigner() + tokenSigner := SeededSigner() testCases := []struct { name string @@ -108,7 +117,7 @@ func VerifyTestSetup(t *testing.T) (rsaKey, ecdsaKey crypto.PublicKey, source [] t.Fatalf("Unable to load certificate for %s: %s", certPath, err.Error()) } rsaKey = cert.PublicKey - gen, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + gen, err := ecdsa.GenerateKey(elliptic.P256(), crand.Reader) if err != nil { t.Fatal("Failed to generate ecdsa key for testing") } diff --git a/src/control/security/testdata/certs/RSA.golden b/src/control/security/testdata/certs/RSA.golden index 3c08d2e629c2b192d81d80f115b39bcfbbf7eb7f..61f546418118ccd2aa25b9c4f4d4cfa87b4c911f 100644 GIT binary patch literal 512 zcmV+b0{{KIFZ3#emGtJBrLS0CzU#uGs!_`CS|{-ne3KFOdx_az{_$xnx0Ex!PI7i& zyPzu?OicWm8B?f;m}+%+UbZbUF?9is8w_e>ID6$0=LRc#rX@(`o@vu&)yv+`Q3Sln zjgERC^GNhboU4thu6I?dBU4^iizIR5&A}_i!`sLOdSX|om37XnvVP7t)GfkG*v3s} z$IUY#mla+=++b&3go8X)MDbD0#CreHQM?kMb@tEt&{J4m>>feIAJ z>I7KBA%<$>Kv6bgZM2r%45se5_EtMNJZYT<42=fDXlEBF5nny^={ugOUX+-C_hYPv zLaII>g;>YPwlXa>2*u6=${m%MSe3YyLNB}syk(;w-gTRls=63&qwBC>ubI!G178G( z?9}GeM1S{|1R4`gVzd9bcYMYi?Z;pwa8I1u!YD9N<$1c9-}$4UeBk8z9=K;` zwntx~+z_j1Xi#Wl_86WWH~pzWIw|Dd1bEaM=&_xK({da0fbM4v4V6`v4p`I)sSTCO zo;;+H`B-)K3yX~bQkcM2dQ8sQbD^FTTA*(x%@Yz|@x*C}wQ*JB&bx>9MD2YpP*l3b z?e~00P=llJ8QEK&yDd8Bo(Tx68eE`s*Zr0 zdtl*Q{;7Cr#BEFo5liA>7sL{@u9YeTTN$*EBaW!;^hCf(MI6WoGWZD%4XA!KPUU{U z528LDZz!vuq3~0cH2eP}DBcm%A1$Q%XRX_H<LE5i#2> z#T(}Z5{G3T2b{voej;ux!1cwjBZy(0AT{skJ1+-w6QvQ)vPBpso$%fs;`ef02A%SR z;w#6;vT$ZmnsG2!g@g8N)d(~;rkCj5^io^pVSs CrUH!s diff --git a/utils/certs/gen_certificates.sh b/utils/certs/gen_certificates.sh index c97bf16b8e7..7cb9c622ea3 100755 --- a/utils/certs/gen_certificates.sh +++ b/utils/certs/gen_certificates.sh @@ -115,10 +115,10 @@ extendedKeyUsage = clientAuth function generate_ca_cert () { echo "Generating Private CA Root Certificate" # Generate Private key and set permissions - openssl genrsa -out "${PRIVATE}/daosCA.key" 4096 + openssl genrsa -out "${PRIVATE}/daosCA.key" 3072 chmod 0400 "${PRIVATE}/daosCA.key" # Generate CA Certificate - openssl req -new -x509 -config "${CA_HOME}/ca.cnf" -days 1095 -sha512 \ + openssl req -new -x509 -config "${CA_HOME}/ca.cnf" -days 365 -sha512 \ -key "${PRIVATE}/daosCA.key" \ -out "${CERTS}/daosCA.crt" -batch # Reset the the CA index @@ -131,7 +131,7 @@ function generate_ca_cert () { function generate_agent_cert () { echo "Generating Agent Certificate" # Generate Private key and set its permissions - openssl genrsa -out "${CERTS}/agent.key" 4096 + openssl genrsa -out "${CERTS}/agent.key" 3072 chmod 0400 "${CERTS}/agent.key" # Generate a Certificate Signing Request (CRS) openssl req -new -config "${CONFIGS}/agent.cnf" -key "${CERTS}/agent.key" \ @@ -151,7 +151,7 @@ function generate_agent_cert () { function generate_admin_cert () { echo "Generating Admin Certificate" # Generate Private key and set its permissions - openssl genrsa -out "${CERTS}/admin.key" 4096 + openssl genrsa -out "${CERTS}/admin.key" 3072 chmod 0400 "${CERTS}/admin.key" # Generate a Certificate Signing Request (CRS) openssl req -new -config "${CONFIGS}/admin.cnf" -key "${CERTS}/admin.key" \ @@ -171,7 +171,7 @@ function generate_admin_cert () { function generate_server_cert () { echo "Generating Server Certificate" # Generate Private key and set its permissions - openssl genrsa -out "${CERTS}/server.key" 4096 + openssl genrsa -out "${CERTS}/server.key" 3072 chmod 0400 "${CERTS}/server.key" # Generate a Certificate Signing Request (CRS) openssl req -new -config "${CONFIGS}/server.cnf" \ @@ -196,7 +196,7 @@ function generate_test_cert () { echo "Generating Test Certificate" # Generate Private key and set its permissions - openssl genrsa -out "${CERTS}/test.key" 4096 + openssl genrsa -out "${CERTS}/test.key" 3072 chmod 0400 "${CERTS}/test.key" # Generate a Certificate Signing Request (CRS) openssl req -new -config "${CONFIGS}/test.cnf" -key "${CERTS}/test.key" \