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