github.com/opentofu/opentofu@v1.7.1/internal/encryption/keyprovider/pbkdf2/compliance_test.go (about) 1 // Copyright (c) The OpenTofu Authors 2 // SPDX-License-Identifier: MPL-2.0 3 // Copyright (c) 2023 HashiCorp, Inc. 4 // SPDX-License-Identifier: MPL-2.0 5 6 package pbkdf2 7 8 import ( 9 "crypto/rand" 10 "fmt" 11 "testing" 12 13 "github.com/opentofu/opentofu/internal/encryption/keyprovider" 14 "github.com/opentofu/opentofu/internal/encryption/keyprovider/compliancetest" 15 ) 16 17 func TestCompliance(t *testing.T) { 18 validConfig := &Config{ 19 randomSource: rand.Reader, 20 Passphrase: "Hello world! 123", 21 KeyLength: DefaultKeyLength, 22 Iterations: DefaultIterations, 23 HashFunction: SHA256HashFunctionName, 24 SaltLength: DefaultSaltLength, 25 } 26 compliancetest.ComplianceTest( 27 t, 28 compliancetest.TestConfiguration[*descriptor, *Config, *Metadata, *pbkdf2KeyProvider]{ 29 Descriptor: New().(*descriptor), 30 HCLParseTestCases: map[string]compliancetest.HCLParseTestCase[*Config, *pbkdf2KeyProvider]{ 31 "empty": { 32 HCL: `key_provider "pbkdf2" "foo" { 33 }`, 34 ValidHCL: false, 35 ValidBuild: false, 36 Validate: nil, 37 }, 38 "basic": { 39 HCL: `key_provider "pbkdf2" "foo" { 40 passphrase = "Hello world! 123" 41 }`, 42 ValidHCL: true, 43 ValidBuild: true, 44 Validate: func(config *Config, keyProvider *pbkdf2KeyProvider) error { 45 if config.Passphrase != "Hello world! 123" { 46 return fmt.Errorf("invalid passphrase after HCL parsing") 47 } 48 if keyProvider.Passphrase != "Hello world! 123" { 49 return fmt.Errorf("invalid passphrase in key provideer") 50 } 51 return nil 52 }, 53 }, 54 "extended": { 55 HCL: fmt.Sprintf(`key_provider "pbkdf2" "foo" { 56 passphrase = "Hello world! 123" 57 key_length = %d 58 iterations = %d 59 salt_length = %d 60 hash_function = "%s" 61 }`, DefaultKeyLength+1, DefaultIterations+1, DefaultSaltLength+1, SHA256HashFunctionName), 62 ValidHCL: true, 63 ValidBuild: true, 64 Validate: func(config *Config, keyProvider *pbkdf2KeyProvider) error { 65 if config.KeyLength != DefaultKeyLength+1 { 66 return fmt.Errorf("incorrect key length after HCL parsing: %d", config.KeyLength) 67 } 68 if config.Iterations != DefaultIterations+1 { 69 return fmt.Errorf("incorrect iterations after HCL parsing: %d", config.Iterations) 70 } 71 if config.SaltLength != DefaultSaltLength+1 { 72 return fmt.Errorf("incorrect salt length after HCL parsing: %d", config.SaltLength) 73 } 74 if config.HashFunction != SHA256HashFunctionName { 75 return fmt.Errorf("incorrect hash function after HCL parsing: %s", config.HashFunction) 76 } 77 return nil 78 }, 79 }, 80 "short-passphrase": { 81 HCL: `key_provider "pbkdf2" "foo" { 82 passphrase = "Hello world! 12" 83 }`, 84 ValidHCL: true, 85 ValidBuild: false, 86 }, 87 "too-small-iterations": { 88 HCL: fmt.Sprintf(`key_provider "pbkdf2" "foo" { 89 passphrase = "Hello world! 123" 90 iterations = %d 91 }`, MinimumIterations-1), 92 ValidHCL: true, 93 ValidBuild: false, 94 }, 95 "invalid-hash-function": { 96 HCL: `key_provider "pbkdf2" "foo" { 97 passphrase = "Hello world! 123" 98 hash_function = "non_existent" 99 }`, 100 ValidHCL: true, 101 ValidBuild: false, 102 }, 103 }, 104 ConfigStructTestCases: map[string]compliancetest.ConfigStructTestCase[*Config, *pbkdf2KeyProvider]{}, 105 MetadataStructTestCases: map[string]compliancetest.MetadataStructTestCase[*Config, *Metadata]{ 106 "not-present-salt": { 107 ValidConfig: validConfig, 108 Meta: &Metadata{ 109 Salt: nil, 110 Iterations: DefaultIterations, 111 HashFunction: SHA256HashFunctionName, 112 KeyLength: 32, 113 }, 114 IsPresent: false, 115 }, 116 "not-present-iterations": { 117 ValidConfig: validConfig, 118 Meta: &Metadata{ 119 Salt: []byte("Hello world!"), 120 Iterations: 0, 121 HashFunction: SHA256HashFunctionName, 122 KeyLength: 32, 123 }, 124 IsPresent: false, 125 }, 126 "not-present-hash-func": { 127 ValidConfig: validConfig, 128 Meta: &Metadata{ 129 Salt: []byte("Hello world!"), 130 Iterations: DefaultIterations, 131 HashFunction: "", 132 KeyLength: 32, 133 }, 134 IsPresent: false, 135 }, 136 "not-present-key-length": { 137 ValidConfig: validConfig, 138 Meta: &Metadata{ 139 Salt: []byte("Hello world!"), 140 Iterations: DefaultIterations, 141 HashFunction: SHA256HashFunctionName, 142 KeyLength: 0, 143 }, 144 IsPresent: false, 145 }, 146 "present-valid": { 147 ValidConfig: validConfig, 148 Meta: &Metadata{ 149 Salt: []byte("Hello world!"), 150 Iterations: DefaultIterations, 151 HashFunction: SHA256HashFunctionName, 152 KeyLength: 32, 153 }, 154 IsPresent: true, 155 IsValid: true, 156 }, 157 "present-valid-too-few-iterations": { 158 ValidConfig: validConfig, 159 Meta: &Metadata{ 160 Salt: []byte("Hello world!"), 161 Iterations: MinimumIterations - 1, 162 HashFunction: SHA256HashFunctionName, 163 KeyLength: 32, 164 }, 165 IsPresent: true, 166 IsValid: true, 167 }, 168 "invalid-iterations": { 169 ValidConfig: validConfig, 170 Meta: &Metadata{ 171 Salt: []byte("Hello world!"), 172 Iterations: -1, 173 HashFunction: SHA256HashFunctionName, 174 KeyLength: 32, 175 }, 176 IsPresent: true, 177 IsValid: false, 178 }, 179 "invalid-salt-length": { 180 ValidConfig: validConfig, 181 Meta: &Metadata{ 182 Salt: []byte("Hello world!"), 183 Iterations: DefaultIterations, 184 HashFunction: SHA256HashFunctionName, 185 KeyLength: -1, 186 }, 187 IsPresent: true, 188 IsValid: false, 189 }, 190 }, 191 ProvideTestCase: compliancetest.ProvideTestCase[*Config, *Metadata]{ 192 ValidConfig: &Config{ 193 randomSource: &testRandomSource{t: t}, 194 Passphrase: "Hello world! 123", 195 KeyLength: DefaultKeyLength, 196 Iterations: DefaultIterations, 197 HashFunction: DefaultHashFunctionName, 198 SaltLength: DefaultSaltLength, 199 }, 200 ExpectedOutput: &keyprovider.Output{ 201 EncryptionKey: []byte{87, 192, 98, 53, 186, 42, 63, 139, 58, 118, 223, 169, 46, 84, 139, 29, 130, 59, 247, 106, 82, 61, 235, 144, 97, 131, 60, 229, 195, 109, 81, 111}, 202 DecryptionKey: []byte{87, 192, 98, 53, 186, 42, 63, 139, 58, 118, 223, 169, 46, 84, 139, 29, 130, 59, 247, 106, 82, 61, 235, 144, 97, 131, 60, 229, 195, 109, 81, 111}, 203 }, 204 ValidateKeys: nil, 205 ValidateMetadata: func(meta *Metadata) error { 206 if !meta.isPresent() { 207 return fmt.Errorf("output metadata is not present") 208 } 209 if err := meta.validate(); err != nil { 210 return err 211 } 212 if meta.KeyLength != DefaultKeyLength { 213 return fmt.Errorf("incorrect output metadata key length: %d", meta.KeyLength) 214 } 215 if meta.Iterations != DefaultIterations { 216 return fmt.Errorf("incorrect output metadata iterations: %d", meta.Iterations) 217 } 218 if len(meta.Salt) != DefaultSaltLength { 219 return fmt.Errorf("incorrect output salt length: %d", len(meta.Salt)) 220 } 221 if meta.HashFunction != DefaultHashFunctionName { 222 return fmt.Errorf("incorrect output hash function name: %s", meta.HashFunction) 223 } 224 return nil 225 }, 226 }, 227 }, 228 ) 229 }