github.com/graywolf-at-work-2/terraform-vendor@v1.4.5/internal/getproviders/package_authentication_test.go (about) 1 package getproviders 2 3 import ( 4 "crypto/sha256" 5 "encoding/base64" 6 "errors" 7 "fmt" 8 "strings" 9 "testing" 10 11 "github.com/google/go-cmp/cmp" 12 13 // TODO: replace crypto/openpgp since it is deprecated 14 // https://github.com/golang/go/issues/44226 15 //lint:file-ignore SA1019 openpgp is deprecated but there are no good alternatives yet 16 "golang.org/x/crypto/openpgp" 17 ) 18 19 func TestPackageAuthenticationResult(t *testing.T) { 20 tests := []struct { 21 result *PackageAuthenticationResult 22 want string 23 }{ 24 { 25 nil, 26 "unauthenticated", 27 }, 28 { 29 &PackageAuthenticationResult{result: verifiedChecksum}, 30 "verified checksum", 31 }, 32 { 33 &PackageAuthenticationResult{result: officialProvider}, 34 "signed by HashiCorp", 35 }, 36 { 37 &PackageAuthenticationResult{result: partnerProvider}, 38 "signed by a HashiCorp partner", 39 }, 40 { 41 &PackageAuthenticationResult{result: communityProvider}, 42 "self-signed", 43 }, 44 } 45 for _, test := range tests { 46 if got := test.result.String(); got != test.want { 47 t.Errorf("wrong value: got %q, want %q", got, test.want) 48 } 49 } 50 } 51 52 // mockAuthentication is an implementation of the PackageAuthentication 53 // interface which returns fixed values. This is used to test the combining 54 // logic of PackageAuthenticationAll. 55 type mockAuthentication struct { 56 result packageAuthenticationResult 57 err error 58 } 59 60 func (m mockAuthentication) AuthenticatePackage(localLocation PackageLocation) (*PackageAuthenticationResult, error) { 61 if m.err == nil { 62 return &PackageAuthenticationResult{result: m.result}, nil 63 } else { 64 return nil, m.err 65 } 66 } 67 68 var _ PackageAuthentication = (*mockAuthentication)(nil) 69 70 // If all authentications succeed, the returned result should come from the 71 // last authentication. 72 func TestPackageAuthenticationAll_success(t *testing.T) { 73 result, err := PackageAuthenticationAll( 74 &mockAuthentication{result: verifiedChecksum}, 75 &mockAuthentication{result: communityProvider}, 76 ).AuthenticatePackage(nil) 77 78 want := PackageAuthenticationResult{result: communityProvider} 79 if result == nil || *result != want { 80 t.Errorf("wrong result: want %#v, got %#v", want, result) 81 } 82 if err != nil { 83 t.Errorf("wrong err: got %#v, want nil", err) 84 } 85 } 86 87 // If an authentication fails, its error should be returned along with a nil 88 // result. 89 func TestPackageAuthenticationAll_failure(t *testing.T) { 90 someError := errors.New("some error") 91 result, err := PackageAuthenticationAll( 92 &mockAuthentication{result: verifiedChecksum}, 93 &mockAuthentication{err: someError}, 94 &mockAuthentication{result: communityProvider}, 95 ).AuthenticatePackage(nil) 96 97 if result != nil { 98 t.Errorf("wrong result: got %#v, want nil", result) 99 } 100 if err != someError { 101 t.Errorf("wrong err: got %#v, want %#v", err, someError) 102 } 103 } 104 105 // Package hash authentication requires a zip file or directory fixture and a 106 // known-good set of hashes, of which the authenticator will pick one. The 107 // result should be "verified checksum". 108 func TestPackageHashAuthentication_success(t *testing.T) { 109 // Location must be a PackageLocalArchive path 110 location := PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64") 111 112 wantHashes := []Hash{ 113 // Known-good HashV1 result for this directory 114 Hash("h1:qjsREM4DqEWECD43FcPqddZ9oxCG+IaMTxvWPciS05g="), 115 } 116 117 auth := NewPackageHashAuthentication(Platform{"linux", "amd64"}, wantHashes) 118 result, err := auth.AuthenticatePackage(location) 119 120 wantResult := PackageAuthenticationResult{result: verifiedChecksum} 121 if result == nil || *result != wantResult { 122 t.Errorf("wrong result: got %#v, want %#v", result, wantResult) 123 } 124 if err != nil { 125 t.Errorf("wrong err: got %s, want nil", err) 126 } 127 } 128 129 // Package has authentication can fail for various reasons. 130 func TestPackageHashAuthentication_failure(t *testing.T) { 131 tests := map[string]struct { 132 location PackageLocation 133 err string 134 }{ 135 "missing file": { 136 PackageLocalArchive("testdata/no-package-here.zip"), 137 "failed to verify provider package checksums: lstat testdata/no-package-here.zip: no such file or directory", 138 }, 139 "checksum mismatch": { 140 PackageLocalDir("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/2.0.0/linux_amd64"), 141 "provider package doesn't match the expected checksum \"h1:invalid\"", 142 }, 143 "invalid zip file": { 144 PackageLocalArchive("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip"), 145 "failed to verify provider package checksums: zip: not a valid zip file", 146 }, 147 } 148 149 for name, test := range tests { 150 t.Run(name, func(t *testing.T) { 151 // Invalid expected hash, either because we'll error before we 152 // reach it, or we want to force a checksum mismatch. 153 auth := NewPackageHashAuthentication(Platform{"linux", "amd64"}, []Hash{"h1:invalid"}) 154 result, err := auth.AuthenticatePackage(test.location) 155 156 if result != nil { 157 t.Errorf("wrong result: got %#v, want nil", result) 158 } 159 if gotErr := err.Error(); gotErr != test.err { 160 t.Errorf("wrong err: got %q, want %q", gotErr, test.err) 161 } 162 }) 163 } 164 } 165 166 // Archive checksum authentication requires a file fixture and a known-good 167 // SHA256 hash. The result should be "verified checksum". 168 func TestArchiveChecksumAuthentication_success(t *testing.T) { 169 // Location must be a PackageLocalArchive path 170 location := PackageLocalArchive("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip") 171 172 // Known-good SHA256 hash for this archive 173 wantSHA256Sum := [sha256.Size]byte{ 174 0x4f, 0xb3, 0x98, 0x49, 0xf2, 0xe1, 0x38, 0xeb, 175 0x16, 0xa1, 0x8b, 0xa0, 0xc6, 0x82, 0x63, 0x5d, 176 0x78, 0x1c, 0xb8, 0xc3, 0xb2, 0x59, 0x01, 0xdd, 177 0x5a, 0x79, 0x2a, 0xde, 0x97, 0x11, 0xf5, 0x01, 178 } 179 180 auth := NewArchiveChecksumAuthentication(Platform{"linux", "amd64"}, wantSHA256Sum) 181 result, err := auth.AuthenticatePackage(location) 182 183 wantResult := PackageAuthenticationResult{result: verifiedChecksum} 184 if result == nil || *result != wantResult { 185 t.Errorf("wrong result: got %#v, want %#v", result, wantResult) 186 } 187 if err != nil { 188 t.Errorf("wrong err: got %s, want nil", err) 189 } 190 } 191 192 // Archive checksum authentication can fail for various reasons. These test 193 // cases are almost exhaustive, missing only an io.Copy error which is 194 // difficult to induce. 195 func TestArchiveChecksumAuthentication_failure(t *testing.T) { 196 tests := map[string]struct { 197 location PackageLocation 198 err string 199 }{ 200 "missing file": { 201 PackageLocalArchive("testdata/no-package-here.zip"), 202 "failed to compute checksum for testdata/no-package-here.zip: lstat testdata/no-package-here.zip: no such file or directory", 203 }, 204 "checksum mismatch": { 205 PackageLocalArchive("testdata/filesystem-mirror/registry.terraform.io/hashicorp/null/terraform-provider-null_2.1.0_linux_amd64.zip"), 206 "archive has incorrect checksum zh:4fb39849f2e138eb16a18ba0c682635d781cb8c3b25901dd5a792ade9711f501 (expected zh:0000000000000000000000000000000000000000000000000000000000000000)", 207 }, 208 "invalid location": { 209 PackageLocalDir("testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64"), 210 "cannot check archive hash for non-archive location testdata/filesystem-mirror/tfe.example.com/AwesomeCorp/happycloud/0.1.0-alpha.2/darwin_amd64", 211 }, 212 } 213 214 for name, test := range tests { 215 t.Run(name, func(t *testing.T) { 216 // Zero expected checksum, either because we'll error before we 217 // reach it, or we want to force a checksum mismatch 218 auth := NewArchiveChecksumAuthentication(Platform{"linux", "amd64"}, [sha256.Size]byte{0}) 219 result, err := auth.AuthenticatePackage(test.location) 220 221 if result != nil { 222 t.Errorf("wrong result: got %#v, want nil", result) 223 } 224 if gotErr := err.Error(); gotErr != test.err { 225 t.Errorf("wrong err: got %q, want %q", gotErr, test.err) 226 } 227 }) 228 } 229 } 230 231 // Matching checksum authentication takes a SHA256SUMS document, an archive 232 // filename, and an expected SHA256 hash. On success both return values should 233 // be nil. 234 func TestMatchingChecksumAuthentication_success(t *testing.T) { 235 // Location is unused 236 location := PackageLocalArchive("testdata/my-package.zip") 237 238 // Two different checksums for other files 239 wantSHA256Sum := [sha256.Size]byte{0xde, 0xca, 0xde} 240 otherSHA256Sum := [sha256.Size]byte{0xc0, 0xff, 0xee} 241 242 document := []byte( 243 fmt.Sprintf( 244 "%x README.txt\n%x my-package.zip\n", 245 otherSHA256Sum, 246 wantSHA256Sum, 247 ), 248 ) 249 filename := "my-package.zip" 250 251 auth := NewMatchingChecksumAuthentication(document, filename, wantSHA256Sum) 252 result, err := auth.AuthenticatePackage(location) 253 254 if result != nil { 255 t.Errorf("wrong result: got %#v, want nil", result) 256 } 257 if err != nil { 258 t.Errorf("wrong err: got %s, want nil", err) 259 } 260 } 261 262 // Matching checksum authentication can fail for three reasons: no checksum 263 // in the document for the filename, invalid checksum value, and non-matching 264 // checksum value. 265 func TestMatchingChecksumAuthentication_failure(t *testing.T) { 266 wantSHA256Sum := [sha256.Size]byte{0xde, 0xca, 0xde} 267 filename := "my-package.zip" 268 269 tests := map[string]struct { 270 document []byte 271 err string 272 }{ 273 "no checksum for filename": { 274 []byte( 275 fmt.Sprintf( 276 "%x README.txt", 277 [sha256.Size]byte{0xbe, 0xef}, 278 ), 279 ), 280 `checksum list has no SHA-256 hash for "my-package.zip"`, 281 }, 282 "invalid checksum": { 283 []byte( 284 fmt.Sprintf( 285 "%s README.txt\n%s my-package.zip", 286 "horses", 287 "chickens", 288 ), 289 ), 290 `checksum list has invalid SHA256 hash "chickens": encoding/hex: invalid byte: U+0068 'h'`, 291 }, 292 "checksum mismatch": { 293 []byte( 294 fmt.Sprintf( 295 "%x README.txt\n%x my-package.zip", 296 [sha256.Size]byte{0xbe, 0xef}, 297 [sha256.Size]byte{0xc0, 0xff, 0xee}, 298 ), 299 ), 300 "checksum list has unexpected SHA-256 hash c0ffee0000000000000000000000000000000000000000000000000000000000 (expected decade0000000000000000000000000000000000000000000000000000000000)", 301 }, 302 } 303 304 for name, test := range tests { 305 t.Run(name, func(t *testing.T) { 306 // Location is unused 307 location := PackageLocalArchive("testdata/my-package.zip") 308 309 auth := NewMatchingChecksumAuthentication(test.document, filename, wantSHA256Sum) 310 result, err := auth.AuthenticatePackage(location) 311 312 if result != nil { 313 t.Errorf("wrong result: got %#v, want nil", result) 314 } 315 if gotErr := err.Error(); gotErr != test.err { 316 t.Errorf("wrong err: got %q, want %q", gotErr, test.err) 317 } 318 }) 319 } 320 } 321 322 // Signature authentication takes a checksum document, a signature, and a list 323 // of signing keys. If the document is signed by one of the given keys, the 324 // authentication is successful. The value of the result depends on the signing 325 // key and its trust signature. 326 func TestSignatureAuthentication_success(t *testing.T) { 327 tests := map[string]struct { 328 signature string 329 keys []SigningKey 330 result PackageAuthenticationResult 331 }{ 332 "partner provider": { 333 testAuthorSignatureGoodBase64, 334 []SigningKey{ 335 { 336 ASCIIArmor: testAuthorKeyArmor, 337 TrustSignature: testAuthorKeyTrustSignatureArmor, 338 }, 339 }, 340 PackageAuthenticationResult{ 341 result: partnerProvider, 342 KeyID: testAuthorKeyID, 343 }, 344 }, 345 "community provider": { 346 testAuthorSignatureGoodBase64, 347 []SigningKey{ 348 { 349 ASCIIArmor: testAuthorKeyArmor, 350 }, 351 }, 352 PackageAuthenticationResult{ 353 result: communityProvider, 354 KeyID: testAuthorKeyID, 355 }, 356 }, 357 "multiple signing keys": { 358 testAuthorSignatureGoodBase64, 359 []SigningKey{ 360 { 361 ASCIIArmor: HashicorpPartnersKey, 362 }, 363 { 364 ASCIIArmor: testAuthorKeyArmor, 365 }, 366 }, 367 PackageAuthenticationResult{ 368 result: communityProvider, 369 KeyID: testAuthorKeyID, 370 }, 371 }, 372 } 373 374 for name, test := range tests { 375 t.Run(name, func(t *testing.T) { 376 // Location is unused 377 location := PackageLocalArchive("testdata/my-package.zip") 378 379 signature, err := base64.StdEncoding.DecodeString(test.signature) 380 if err != nil { 381 t.Fatal(err) 382 } 383 384 auth := NewSignatureAuthentication([]byte(testShaSumsPlaceholder), signature, test.keys) 385 result, err := auth.AuthenticatePackage(location) 386 387 if result == nil || *result != test.result { 388 t.Errorf("wrong result: got %#v, want %#v", result, test.result) 389 } 390 if err != nil { 391 t.Errorf("wrong err: got %s, want nil", err) 392 } 393 }) 394 } 395 } 396 397 func TestNewSignatureAuthentication_success(t *testing.T) { 398 tests := map[string]struct { 399 signature string 400 keys []SigningKey 401 result PackageAuthenticationResult 402 }{ 403 "official provider": { 404 testHashicorpSignatureGoodBase64, 405 []SigningKey{ 406 { 407 ASCIIArmor: HashicorpPublicKey, 408 }, 409 }, 410 PackageAuthenticationResult{ 411 result: officialProvider, 412 KeyID: testHashiCorpPublicKeyID, 413 }, 414 }, 415 } 416 417 for name, test := range tests { 418 t.Run(name, func(t *testing.T) { 419 // Location is unused 420 location := PackageLocalArchive("testdata/my-package.zip") 421 422 signature, err := base64.StdEncoding.DecodeString(test.signature) 423 if err != nil { 424 t.Fatal(err) 425 } 426 427 auth := NewSignatureAuthentication([]byte(testProviderShaSums), signature, test.keys) 428 result, err := auth.AuthenticatePackage(location) 429 430 if result == nil || *result != test.result { 431 t.Errorf("wrong result: got %#v, want %#v", result, test.result) 432 } 433 if err != nil { 434 t.Errorf("wrong err: got %s, want nil", err) 435 } 436 }) 437 } 438 } 439 440 // Signature authentication can fail for many reasons, most of which are due 441 // to OpenPGP failures from malformed keys or signatures. 442 func TestSignatureAuthentication_failure(t *testing.T) { 443 tests := map[string]struct { 444 signature string 445 keys []SigningKey 446 err string 447 }{ 448 "invalid key": { 449 testHashicorpSignatureGoodBase64, 450 []SigningKey{ 451 { 452 ASCIIArmor: "invalid PGP armor value", 453 }, 454 }, 455 "error decoding signing key: openpgp: invalid argument: no armored data found", 456 }, 457 "invalid signature": { 458 testSignatureBadBase64, 459 []SigningKey{ 460 { 461 ASCIIArmor: testAuthorKeyArmor, 462 }, 463 }, 464 "error checking signature: openpgp: invalid data: signature subpacket truncated", 465 }, 466 "no keys match signature": { 467 testAuthorSignatureGoodBase64, 468 []SigningKey{ 469 { 470 ASCIIArmor: HashicorpPublicKey, 471 }, 472 }, 473 "authentication signature from unknown issuer", 474 }, 475 "invalid trust signature": { 476 testAuthorSignatureGoodBase64, 477 []SigningKey{ 478 { 479 ASCIIArmor: testAuthorKeyArmor, 480 TrustSignature: "invalid PGP armor value", 481 }, 482 }, 483 "error decoding trust signature: EOF", 484 }, 485 "unverified trust signature": { 486 testAuthorSignatureGoodBase64, 487 []SigningKey{ 488 { 489 ASCIIArmor: testAuthorKeyArmor, 490 TrustSignature: testOtherKeyTrustSignatureArmor, 491 }, 492 }, 493 "error verifying trust signature: openpgp: invalid signature: hash tag doesn't match", 494 }, 495 } 496 497 for name, test := range tests { 498 t.Run(name, func(t *testing.T) { 499 // Location is unused 500 location := PackageLocalArchive("testdata/my-package.zip") 501 502 signature, err := base64.StdEncoding.DecodeString(test.signature) 503 if err != nil { 504 t.Fatal(err) 505 } 506 507 auth := NewSignatureAuthentication([]byte(testShaSumsPlaceholder), signature, test.keys) 508 result, err := auth.AuthenticatePackage(location) 509 510 if result != nil { 511 t.Errorf("wrong result: got %#v, want nil", result) 512 } 513 if gotErr := err.Error(); gotErr != test.err { 514 t.Errorf("wrong err: got %s, want %s", gotErr, test.err) 515 } 516 }) 517 } 518 } 519 520 func TestSignatureAuthentication_acceptableHashes(t *testing.T) { 521 auth := NewSignatureAuthentication([]byte(testShaSumsRealistic), nil, nil) 522 authWithHashes, ok := auth.(PackageAuthenticationHashes) 523 if !ok { 524 t.Fatalf("%T does not implement PackageAuthenticationHashes", auth) 525 } 526 got := authWithHashes.AcceptableHashes() 527 want := []Hash{ 528 // These are the hashes encoded in constant testShaSumsRealistic 529 "zh:7d7e888fdd28abfe00894f9055209b9eec785153641de98e6852aa071008d4ee", 530 "zh:f8b6cf9ade087c17826d49d89cef21261cdc22bd27065bbc5b27d7dbf7fbbf6c", 531 "zh:a5ba9945606bb7bfb821ba303957eeb40dd9ee4e706ba8da1eaf7cbeb0356e63", 532 "zh:df3a5a8d6ffff7bacf19c92d10d0d500f98169ea17b3764b01a789f563d1aad7", 533 "zh:086119a26576d06b8281a97e8644380da89ce16197cd955f74ea5ee664e9358b", 534 "zh:1e5f7a5f3ade7b8b1d1d59c5cea2e1a2f8d2f8c3f41962dbbe8647e222be8239", 535 "zh:0e9fd0f3e2254b526a0e81e0cfdfc82583b0cd343778c53ead21aa7d52f776d7", 536 "zh:66a947e7de1c74caf9f584c3ed4e91d2cb1af6fe5ce8abaf1cf8f7ff626a09d1", 537 "zh:def1b73849bec0dc57a04405847921bf9206c75b52ae9de195476facb26bd85e", 538 "zh:48f1826ec31d6f104e46cc2022b41f30cd1019ef48eaec9697654ef9ec37a879", 539 "zh:17e0b496022bc4e4137be15e96d2b051c8acd6e14cb48d9b13b262330464f6cc", 540 "zh:2696c86228f491bc5425561c45904c9ce39b1c676b1e17734cb2ee6b578c4bcd", 541 } 542 if diff := cmp.Diff(want, got); diff != "" { 543 t.Errorf("wrong result\n%s", diff) 544 } 545 } 546 547 const testAuthorKeyID = `37A6AB3BCF2C170A` 548 549 // testAuthorKeyArmor is test key ID 5BFEEC4317E746008621970637A6AB3BCF2C170A. 550 const testAuthorKeyArmor = `-----BEGIN PGP PUBLIC KEY BLOCK----- 551 552 mQENBF5vhgYBCAC40OcC2hEx3yGiLhHMbt7DAVEQ0nZwAWy6oL98niknLumBa1VO 553 nMYshP+o/FKOFatBl8aXhmDo606P6pD9d4Pg/WNehqT7hGNHcAFlm+8qjQAvE5uX 554 Z/na/Np7dmWasCiL5hYyHEnKU/XFpc9KyicbkS7n8igP1LEb8xDD1pMLULQsQHA4 555 258asvtwjoYTZIij1I6bUE178bGFPNCfj+FzQM8nKzPpDVxZ7njN9c2sB9FEdJ1+ 556 S9mZQNK5PbJuEAOpD5Jp9BnGE16jsLUhDmvGHBjFZAXMBkNSloEMHhs2ty9lEzoF 557 eJmJx7XCGw+ds1SWp4MsHQPWzXxAlrfa4GMlABEBAAG0R1RlcnJhZm9ybSBUZXN0 558 aW5nIChwbHVnaW4vZGlzY292ZXJ5LykgPHRlcnJhZm9ybSt0ZXN0aW5nQGhhc2hp 559 Y29ycC5jb20+iQFOBBMBCAA4FiEEW/7sQxfnRgCGIZcGN6arO88sFwoFAl5vhgYC 560 GwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AACgkQN6arO88sFwpWvQf/apaMu4Bm 561 ea8AGjdl9acQhHBpWsyiHLIfZvN11xxN/f3+YITvPXIe2PMgveqNfXxu6PIeZGDb 562 0DBvnBQy/vqmA+sCQ8t8+kIWdfZ1EeM2YcXdmAEtriooLvc85JFYjafLIKSj9N7o 563 V/R/e1BCW/v1/7Je47c+6FSt3HHhwyT5AZ3BCq1zpw6PeCDSQ/gZr3Mvq4CjeLA/ 564 K+8TM3KyOF4qBGDvzGzp/t9umQSS2L0ozd90lxJtf5Q8ozqDaBiDo+f/osXT2EvN 565 VwPP/xh/gABkXiNrPylFbeD+XPAC4N7NmYK5aPDzRYXXknP8e9PDMykoJKZ+bSdz 566 F3IZ4q5RDHmmNbkBDQReb4YGAQgAt15e1F8TPQQm1jK8+scypHgfmPHbp7Qsulo1 567 GTcUd8QmhbR4kayuLDEpJYzq6+IoTM4TPqsdVuq/1Nwey9oyK0wXk/SUR29nRIQh 568 3GBg7JVg1YsObsfVTvEflYOdjk8T/Udqs4I6HnmSbtzsaohzybutpWXPUkW8OzFI 569 ATwfVTrrz70Yxs+ly0nSEH2Yf+kg2uYZvv5KsJ3MNENhXnHnlaTy2IfhsxAX0xOG 570 pa9fXV3NzdEbl0mYaEzMi77qRAyIQ9VrIL5F0yY/LlbpLSl6xk2+BB2v3a1Ey6SJ 571 w4/le6AM0wlH2hKPCTlkvM0IvUWjlzrPzCkeu027iVc+fqdyiQARAQABiQE2BBgB 572 CAAgFiEEW/7sQxfnRgCGIZcGN6arO88sFwoFAl5vhgYCGwwACgkQN6arO88sFwqz 573 nAf/eF4oZG9F8sJX01mVdDm/L7Uthe4xjTdl7jwV4ygNX+pCyWrww3qc3qbd3QKg 574 CFqIt/TAPE/OxHxCFuxalQefpOqfxjKzvcktxzWmpgxaWsvHaXiS4bKBPz78N/Ke 575 MUtcjGHyLeSzYPUfjquqDzQxqXidRYhyHGSy9c0NKZ6wCElLZ6KcmCQb4sZxVwfu 576 ssjwAFbPMp1nr0f5SWCJfhTh7QF7lO2ldJaKMlcBM8aebmqFQ52P7ZWOFcgeerng 577 G7Zdrci1KEd943HhzDCsUFz4gJwbvUyiAYb2ddndpUBkYwCB/XrHWPOSnGxHgZoo 578 1gIqed9OV/+s5wKxZPjL0pCStQ== 579 =mYqJ 580 -----END PGP PUBLIC KEY BLOCK-----` 581 582 // testAuthorKeyTrustSignatureArmor is a trust signature of the data in 583 // testAuthorKeyArmor signed with HashicorpPartnersKey. 584 const testAuthorKeyTrustSignatureArmor = `-----BEGIN PGP SIGNATURE----- 585 586 iQIzBAABCAAdFiEEUYkGV8Ws20uCMIZWfXLUJo5GYPwFAl5w9+YACgkQfXLUJo5G 587 YPwjRBAAvy9jo3vvetb4qx/z2qhbRH2JbZN9byKuqlIggPzDhhaIsVJVZ9L6H6bE 588 AMgPe/NaH58wfiqMYenulYxj9tZwJORT/OK0Y9ZFXXZk6kWPMNv7TEppyB0wKgqq 589 ORKf07KjDcVQslDG9ARgnvDq2GA4UTHxhT0chKHdIKeDLmTm0VSkfNeOhQIkW7vB 590 S/WT9y78319QJek8OKwJo0Jv0O93rvZZI0JFjXGtP15XNBfObMtPXn3l8qoLzhsv 591 pJJG/u+BsVZ+y1JDQQlHaD1P2TLW/nGymFq12k693IOCmNyaIOa01Wa9B/j3a3RY 592 v4SdkULvJKbttNMNBgIMJ74wZp5EUhEFs68sllrIrmthH8bW2fbcHEQ1g/MJCe3+ 593 43c9aoW8yNQmuEe7yre9lgqcJOIOxlb5XEJhH0Lh+8OBi5aHA/5wXGU5WrhWqHCR 594 npXBsNqy2sKUuVkEzvn3Hd6aoKncVLrgNR8xA3VP86jJhawvO+M+YYMr1wOVHc/I 595 PYq9hlyUR8qJ/0RpnaIE1iLbPYfEpGTg7oHORpbQVoZAUwMN/Sdox7sMkqCOb1RJ 596 Cmy9J5o7iiNOoshvps5cxcbsM7LNfbf0vDhWpckAvsQehrS1mfVuFHkIiotVQhH1 597 QXPfvB2cVF/SxMqqHWpnT+8c8klfS03kXSb0BdknrQ4DNPq1H5A= 598 =3A1s 599 -----END PGP SIGNATURE-----` 600 601 // testOtherKeyTrustSignatureArmor is a trust signature of another key (not the 602 // author key), signed with HashicorpPartnersKey. 603 const testOtherKeyTrustSignatureArmor = `-----BEGIN PGP SIGNATURE----- 604 605 iQIzBAABCAAdFiEEUYkGV8Ws20uCMIZWfXLUJo5GYPwFAl6POvsACgkQfXLUJo5G 606 YPyGihAAomM1kGmrC5KRgWQ+V47r8wFoIkhsTgAYb9ENOzn/RVJt3SJSstcKxfA3 607 7HW5R4kqAoXH1hcPYpUcOcdeAvtZxjGRQ9JgErV8NBg6sR11aQccCzAG4Hy0hWav 608 /jB5NzTEX5JFEXH6WhpWI1avh0l2j6JxO1K1s+5+5PI3KbuO+XSqeZ3QmUz9FwGu 609 pr0J6oYcERupzrpnmgMb5fbkpHfzffR2/MOYdF9Hae4EvDS1b7tokuuKsStNnCm0 610 ge7PFdekwbj/OiQrQlqM1pOw2siPX3ouWCtW8oExm9tAxNw31Bn2g3oaNMkHMqJd 611 hlVUZlqeJMyylUat3cY7GTQONfCnoyUHe/wv8exBUbV3v2glp9y2g9i2XmXkHOrV 612 Z+pnNBc+jdp3a4O0Y8fXXZdjiIolZKY8BbvzheuMrQQIOmw4N3KrZbTpLKuqz8rb 613 h8bqUbU42oWcJmBvzF4NZ4tQ+aFHs4CbOnjfDfS14baQr2Gqo9BqTfrzS5Pbs8lq 614 AhY0r+zi71lQ1rBfgZfjd8zWlOzpDO//nwKhGCqYOWke/C/T6o0zxM0R4uR4zXwT 615 KhvXK8/kK/L8Flaxqme0d5bzXLbsMe9I6I76DY5iNhkiFnnWt4+FhGoIDR03MTKS 616 SnHodBLlpKLyUXi36DCDy/iKVsieqLsAdcYe0nQFuhoQcOme33A= 617 =aHOG 618 -----END PGP SIGNATURE-----` 619 620 // testShaSumsPlaceholder is a string that represents a signed document that 621 // the signature authenticator will check. Some of the signature valuesin 622 // other constants in this file are signing this string. 623 const testShaSumsPlaceholder = "example shasums data" 624 625 // testShaSumsRealistic is a more realistic SHA256SUMS document that we can use 626 // to test the AcceptableHashes method. The signature values in other constants 627 // in this file do not sign this string. 628 const testShaSumsRealistic = `7d7e888fdd28abfe00894f9055209b9eec785153641de98e6852aa071008d4ee terraform_0.14.0-alpha20200923_darwin_amd64.zip 629 f8b6cf9ade087c17826d49d89cef21261cdc22bd27065bbc5b27d7dbf7fbbf6c terraform_0.14.0-alpha20200923_freebsd_386.zip 630 a5ba9945606bb7bfb821ba303957eeb40dd9ee4e706ba8da1eaf7cbeb0356e63 terraform_0.14.0-alpha20200923_freebsd_amd64.zip 631 df3a5a8d6ffff7bacf19c92d10d0d500f98169ea17b3764b01a789f563d1aad7 terraform_0.14.0-alpha20200923_freebsd_arm.zip 632 086119a26576d06b8281a97e8644380da89ce16197cd955f74ea5ee664e9358b terraform_0.14.0-alpha20200923_linux_386.zip 633 1e5f7a5f3ade7b8b1d1d59c5cea2e1a2f8d2f8c3f41962dbbe8647e222be8239 terraform_0.14.0-alpha20200923_linux_amd64.zip 634 0e9fd0f3e2254b526a0e81e0cfdfc82583b0cd343778c53ead21aa7d52f776d7 terraform_0.14.0-alpha20200923_linux_arm.zip 635 66a947e7de1c74caf9f584c3ed4e91d2cb1af6fe5ce8abaf1cf8f7ff626a09d1 terraform_0.14.0-alpha20200923_openbsd_386.zip 636 def1b73849bec0dc57a04405847921bf9206c75b52ae9de195476facb26bd85e terraform_0.14.0-alpha20200923_openbsd_amd64.zip 637 48f1826ec31d6f104e46cc2022b41f30cd1019ef48eaec9697654ef9ec37a879 terraform_0.14.0-alpha20200923_solaris_amd64.zip 638 17e0b496022bc4e4137be15e96d2b051c8acd6e14cb48d9b13b262330464f6cc terraform_0.14.0-alpha20200923_windows_386.zip 639 2696c86228f491bc5425561c45904c9ce39b1c676b1e17734cb2ee6b578c4bcd terraform_0.14.0-alpha20200923_windows_amd64.zip` 640 641 // testAuthorSignatureGoodBase64 is a signature of testShaSums signed with 642 // testAuthorKeyArmor, which represents the SHA256SUMS.sig file downloaded for 643 // a release. 644 const testAuthorSignatureGoodBase64 = `iQEzBAABCAAdFiEEW/7sQxfnRgCGIZcGN6arO88s` + 645 `FwoFAl5vh7gACgkQN6arO88sFwrAlQf6Al77qzjxNIj+NQNJfBGYUE5jHIgcuWOs1IPRTYUI` + 646 `rHQIUU2RVrdHoAefKTKNzGde653JK/pYTflSV+6ini3/aZZnXlF6t001w3wswmakdwTr0hXx` + 647 `Ez/hHYio72Gpn7+T/L+nl6dKkjeGqd/Kor5x2TY9uYB737ESmAe5T8ZlPaGMFHh0mYlNTeRq` + 648 `4qIKqL6DwddBF4Ju2svn2MeNMGfE358H31mxAl2k4PPrwBTR1sFUCUOzAXVA/g9Ov5Y9ni2G` + 649 `rkTahBtV9yuUUd1D+oRTTTdP0bj3A+3xxXmKTBhRuvurydPTicKuWzeILIJkcwp7Kl5UbI2N` + 650 `n1ayZdaCIw/r4w==` 651 652 // testSignatureBadBase64 is an invalid signature. 653 const testSignatureBadBase64 = `iQEzBAABCAAdFiEEW/7sQxfnRgCGIZcGN6arO88s` + 654 `4qIKqL6DwddBF4Ju2svn2MeNMGfE358H31mxAl2k4PPrwBTR1sFUCUOzAXVA/g9Ov5Y9ni2G` + 655 `rkTahBtV9yuUUd1D+oRTTTdP0bj3A+3xxXmKTBhRuvurydPTicKuWzeILIJkcwp7Kl5UbI2N` + 656 `n1ayZdaCIw/r4w==` 657 658 // testHashiCorpPublicKeyID is the Key ID of the HashiCorpPublicKey. 659 const testHashiCorpPublicKeyID = `34365D9472D7468F` 660 661 const testProviderShaSums = `fea4227271ebf7d9e2b61b89ce2328c7262acd9fd190e1fd6d15a591abfa848e terraform-provider-null_3.1.0_darwin_amd64.zip 662 9ebf4d9704faba06b3ec7242c773c0fbfe12d62db7d00356d4f55385fc69bfb2 terraform-provider-null_3.1.0_darwin_arm64.zip 663 a6576c81adc70326e4e1c999c04ad9ca37113a6e925aefab4765e5a5198efa7e terraform-provider-null_3.1.0_freebsd_386.zip 664 5f9200bf708913621d0f6514179d89700e9aa3097c77dac730e8ba6e5901d521 terraform-provider-null_3.1.0_freebsd_amd64.zip 665 fc39cc1fe71234a0b0369d5c5c7f876c71b956d23d7d6f518289737a001ba69b terraform-provider-null_3.1.0_freebsd_arm.zip 666 c797744d08a5307d50210e0454f91ca4d1c7621c68740441cf4579390452321d terraform-provider-null_3.1.0_linux_386.zip 667 53e30545ff8926a8e30ad30648991ca8b93b6fa496272cd23b26763c8ee84515 terraform-provider-null_3.1.0_linux_amd64.zip 668 cecb6a304046df34c11229f20a80b24b1603960b794d68361a67c5efe58e62b8 terraform-provider-null_3.1.0_linux_arm64.zip 669 e1371aa1e502000d9974cfaff5be4cfa02f47b17400005a16f14d2ef30dc2a70 terraform-provider-null_3.1.0_linux_arm.zip 670 a8a42d13346347aff6c63a37cda9b2c6aa5cc384a55b2fe6d6adfa390e609c53 terraform-provider-null_3.1.0_windows_386.zip 671 02a1675fd8de126a00460942aaae242e65ca3380b5bb192e8773ef3da9073fd2 terraform-provider-null_3.1.0_windows_amd64.zip 672 ` 673 674 // testHashicorpSignatureGoodBase64 is a signature of testProviderShaSums signed with 675 // HashicorpPublicKey, which represents the SHA256SUMS.sig file downloaded for 676 // an official release. 677 const testHashicorpSignatureGoodBase64 = `wsFcBAABCAAQBQJgga+GCRCwtEEJdoW2dgAA` + 678 `o0YQAAW911BGDr2WHLo5NwcZenwHyxL5DX9g+4BknKbc/WxRC1hD8Afi3eygZk1yR6eT4Gp2H` + 679 `yNOwCjGL1PTONBumMfj9udIeuX8onrJMMvjFHh+bORGxBi4FKr4V3b2ZV1IYOjWMEyyTGRDvw` + 680 `SCdxBkp3apH3s2xZLmRoAj84JZ4KaxGF7hlT0j4IkNyQKd2T5cCByN9DV80+x+HtzaOieFwJL` + 681 `97iyGj6aznXfKfslK6S4oIrVTwyLTrQbxSxA0LsdUjRPHnJamL3sFOG77qUEUoXG3r61yi5vW` + 682 `V4P5gCH/+C+VkfGHqaB1s0jHYLxoTEXtwthe66MydDBPe2Hd0J12u9ppOIeK3leeb4uiixWIi` + 683 `rNdpWyjr/LU1KKWPxsDqMGYJ9TexyWkXjEpYmIEiY1Rxar8jrLh+FqVAhxRJajjgSRu5pZj50` + 684 `CNeKmmbyolLhPCmICjYYU/xKPGXSyDFqonVVyMWCSpO+8F38OmwDQHIk5AWyc8hPOAZ+g5N95` + 685 `cfUAzEqlvmNvVHQIU40Y6/Ip2HZzzFCLKQkMP1aDakYHq5w4ZO/ucjhKuoh1HDQMuMnZSu4eo` + 686 `2nMTBzYZnUxwtROrJZF1t103avbmP2QE/GaPvLIQn7o5WMV3ZcPCJ+szzzby7H2e33WIynrY/` + 687 `95ensBxh7mGFbcQ1C59b5o7viwIaaY2` 688 689 // entityString function is used for logging the signing key. 690 func TestEntityString(t *testing.T) { 691 var tests = []struct { 692 name string 693 entity *openpgp.Entity 694 expected string 695 }{ 696 { 697 "nil", 698 nil, 699 "", 700 }, 701 { 702 "testAuthorKeyArmor", 703 testReadArmoredEntity(t, testAuthorKeyArmor), 704 "37A6AB3BCF2C170A Terraform Testing (plugin/discovery/) <terraform+testing@hashicorp.com>", 705 }, 706 { 707 "HashicorpPublicKey", 708 testReadArmoredEntity(t, HashicorpPublicKey), 709 "34365D9472D7468F HashiCorp Security (hashicorp.com/security) <security@hashicorp.com>", 710 }, 711 { 712 "HashicorpPartnersKey", 713 testReadArmoredEntity(t, HashicorpPartnersKey), 714 "7D72D4268E4660FC HashiCorp Security (Terraform Partner Signing) <security+terraform@hashicorp.com>", 715 }, 716 } 717 718 for _, tt := range tests { 719 t.Run(tt.name, func(t *testing.T) { 720 actual := entityString(tt.entity) 721 if actual != tt.expected { 722 t.Errorf("expected %s, actual %s", tt.expected, actual) 723 } 724 }) 725 } 726 } 727 728 func testReadArmoredEntity(t *testing.T, armor string) *openpgp.Entity { 729 data := strings.NewReader(armor) 730 731 el, err := openpgp.ReadArmoredKeyRing(data) 732 if err != nil { 733 t.Fatal(err) 734 } 735 736 if count := len(el); count != 1 { 737 t.Fatalf("expected 1 entity, got %d", count) 738 } 739 740 return el[0] 741 }