diff options
Diffstat (limited to 'internal/verify')
| -rw-r--r-- | internal/verify/verify.go | 60 | ||||
| -rw-r--r-- | internal/verify/verify_test.go | 331 |
2 files changed, 339 insertions, 52 deletions
diff --git a/internal/verify/verify.go b/internal/verify/verify.go index e9a9316..50bdd0b 100644 --- a/internal/verify/verify.go +++ b/internal/verify/verify.go @@ -18,13 +18,26 @@ import ( // The return value will either be (true, nil) for a valid signature or (false, VerifyError) otherwise. // // Verify is a wrapper around verifyWithKeys where allowedPublicKeys is set to the list from https://git.sr.ht/~eduvpn/disco.eduvpn.org#public-keys. -func Verify(signatureFileContent string, signedJson []byte, expectedFileName string, minSignTime uint64, forcePrehash bool) (bool, error) { +func Verify( + signatureFileContent string, + signedJson []byte, + expectedFileName string, + minSignTime uint64, + forcePrehash bool, +) (bool, error) { // keys taken from https://git.sr.ht/~eduvpn/disco.eduvpn.org#public-keys keyStrs := []string{ "RWRtBSX1alxyGX+Xn3LuZnWUT0w//B6EmTJvgaAxBMYzlQeI+jdrO6KF", // fkooman@tuxed.net, kolla@uninett.no "RWQKqtqvd0R7rUDp0rWzbtYPA3towPWcLDCl7eY9pBMMI/ohCmrS0WiM", // RoSp } - valid, err := verifyWithKeys(signatureFileContent, signedJson, expectedFileName, minSignTime, keyStrs, forcePrehash) + valid, err := verifyWithKeys( + signatureFileContent, + signedJson, + expectedFileName, + minSignTime, + keyStrs, + forcePrehash, + ) if err != nil { return valid, &types.WrappedErrorMessage{Message: "failed signature verify", Err: err} } @@ -41,12 +54,22 @@ func Verify(signatureFileContent string, signedJson []byte, expectedFileName str // // The return value will either be (true, nil) on success or (false, detailedVerifyError) on failure. // Note that every error path is wrapped in a custom type here because minisign does not return custom error types, they use errors.New -func verifyWithKeys(signatureFileContent string, signedJson []byte, filename string, minSignTime uint64, allowedPublicKeys []string, forcePrehash bool) (bool, error) { +func verifyWithKeys( + signatureFileContent string, + signedJson []byte, + filename string, + minSignTime uint64, + allowedPublicKeys []string, + forcePrehash bool, +) (bool, error) { switch filename { case "server_list.json", "organization_list.json": break default: - return false, &VerifyUnknownExpectedFilenameError{Filename: filename, Expected: "server_list.json or organization_list.json"} + return false, &VerifyUnknownExpectedFilenameError{ + Filename: filename, + Expected: "server_list.json or organization_list.json", + } } sig, err := minisign.DecodeSignature(signatureFileContent) @@ -56,7 +79,10 @@ func verifyWithKeys(signatureFileContent string, signedJson []byte, filename str // Check if signature is prehashed, see https://jedisct1.github.io/minisign/#signature-format if forcePrehash && sig.SignatureAlgorithm != [2]byte{'E', 'D'} { - return false, &VerifyInvalidSignatureAlgorithmError{Algorithm: string(sig.SignatureAlgorithm[:]), WantedAlgorithm: "ED (BLAKE2b-prehashed EdDSA)"} + return false, &VerifyInvalidSignatureAlgorithmError{ + Algorithm: string(sig.SignatureAlgorithm[:]), + WantedAlgorithm: "ED (BLAKE2b-prehashed EdDSA)", + } } // Find allowed key used for signature @@ -80,9 +106,17 @@ func verifyWithKeys(signatureFileContent string, signedJson []byte, filename str var signTime uint64 var sigFileName string // sigFileName cannot have spaces - _, err = fmt.Sscanf(sig.TrustedComment, "trusted comment: timestamp:%d\tfile:%s", &signTime, &sigFileName) + _, err = fmt.Sscanf( + sig.TrustedComment, + "trusted comment: timestamp:%d\tfile:%s", + &signTime, + &sigFileName, + ) if err != nil { - return false, &VerifyInvalidTrustedCommentError{TrustedComment: sig.TrustedComment, Err: err} + return false, &VerifyInvalidTrustedCommentError{ + TrustedComment: sig.TrustedComment, + Err: err, + } } if sigFileName != filename { @@ -127,7 +161,11 @@ type VerifyInvalidSignatureAlgorithmError struct { } func (e *VerifyInvalidSignatureAlgorithmError) Error() string { - return fmt.Sprintf("invalid signature algorithm: %s, wanted: %s", e.Algorithm, e.WantedAlgorithm) + return fmt.Sprintf( + "invalid signature algorithm: %s, wanted: %s", + e.Algorithm, + e.WantedAlgorithm, + ) } type VerifyCreatePublicKeyError struct { @@ -174,7 +212,11 @@ type VerifyWrongSigFilenameError struct { } func (e *VerifyWrongSigFilenameError) Error() string { - return fmt.Sprintf("wrong filename: %s, expected filename: %s for signature", e.Filename, e.SigFilename) + return fmt.Sprintf( + "wrong filename: %s, expected filename: %s for signature", + e.Filename, + e.SigFilename, + ) } type VerifySigTimeEarlierError struct { diff --git a/internal/verify/verify_test.go b/internal/verify/verify_test.go index 7d577dd..47b1dc2 100644 --- a/internal/verify/verify_test.go +++ b/internal/verify/verify_test.go @@ -51,46 +51,278 @@ func Test_verifyWithKeys(t *testing.T) { minSignTime uint64 allowedPks []string }{ - {&verifyInvalidSignatureAlgorithmError, "pure", "server_list.json.pure.minisig", "server_list.json", "server_list.json", 10, pk}, - - {nil, "valid server_list", "server_list.json.minisig", "server_list.json", "server_list.json", 10, pk}, - {nil, "TC no hashed", "server_list.json.tc_nohashed.minisig", "server_list.json", "server_list.json", 10, pk}, - {nil, "TC later time", "server_list.json.tc_latertime.minisig", "server_list.json", "server_list.json", 10, pk}, - {&verifyWrongSigFilenameError, "server_list TC file:organization_list", "server_list.json.tc_orglist.minisig", "server_list.json", "server_list.json", 10, pk}, - {&verifyWrongSigFilenameError, "organization_list as server_list", "organization_list.json.minisig", "organization_list.json", "server_list.json", 10, pk}, - {&verifyWrongSigFilenameError, "TC file:otherfile", "server_list.json.tc_otherfile.minisig", "server_list.json", "server_list.json", 10, pk}, - {&verifySigTimeEarlierError, "TC no file", "server_list.json.tc_nofile.minisig", "server_list.json", "server_list.json", 10, pk}, - {&verifySigTimeEarlierError, "TC no time", "server_list.json.tc_notime.minisig", "server_list.json", "server_list.json", 10, pk}, - {&verifySigTimeEarlierError, "TC empty time", "server_list.json.tc_emptytime.minisig", "server_list.json", "server_list.json", 10, pk}, - {&verifyInvalidSignatureFormatError, "TC empty file", "server_list.json.tc_emptyfile.minisig", "server_list.json", "server_list.json", 10, pk}, - {&verifyInvalidTrustedCommentError, "TC random", "server_list.json.tc_random.minisig", "server_list.json", "server_list.json", 10, pk}, - {nil, "large time", "server_list.json.large_time.minisig", "server_list.json", "server_list.json", 43e8, pk}, - {nil, "lower min time", "server_list.json.minisig", "server_list.json", "server_list.json", 5, pk}, - {&verifySigTimeEarlierError, "higher min time", "server_list.json.minisig", "server_list.json", "server_list.json", 11, pk}, - - {nil, "valid organization_list", "organization_list.json.minisig", "organization_list.json", "organization_list.json", 10, pk}, - {&verifyWrongSigFilenameError, "organization_list TC file:server_list", "organization_list.json.tc_servlist.minisig", "organization_list.json", "organization_list.json", 10, pk}, - {&verifyWrongSigFilenameError, "server_list as organization_list", "server_list.json.minisig", "server_list.json", "organization_list.json", 10, pk}, - - {&verifyUnknownExpectedFilenameError, "valid other_list", "other_list.json.minisig", "other_list.json", "other_list.json", 10, pk}, - {&verifyWrongSigFilenameError, "other_list as server_list", "other_list.json.minisig", "other_list.json", "server_list.json", 10, pk}, - - {&verifyInvalidSignatureFormatError, "invalid signature file", "random.txt", "server_list.json", "server_list.json", 10, pk}, - {&verifyInvalidSignatureFormatError, "empty signature file", "empty", "server_list.json", "server_list.json", 10, pk}, - - {&verifyUnknownKeyError, "wrong key", "server_list.json.wrong_key.minisig", "server_list.json", "server_list.json", 10, pk}, - - {&verifyInvalidSignatureAlgorithmError, "forged pure signature", "server_list.json.forged_pure.minisig", "server_list.json.blake2b", "server_list.json", 10, pk}, - {&verifyInvalidSignatureError, "forged key ID", "server_list.json.forged_keyid.minisig", "server_list.json", "server_list.json", 10, pk}, - - {&verifyUnknownKeyError, "no allowed keys", "server_list.json.minisig", "server_list.json", "server_list.json", 10, []string{}}, - {nil, "multiple allowed keys 1", "server_list.json.minisig", "server_list.json", "server_list.json", 10, []string{ - pk[0], "RWSf0PYToIUJmDlsz21YOXvgQzHj9NSdyJUqEY5ZdfS9GepeXt3+JJRZ", - }}, - {nil, "multiple allowed keys 2", "server_list.json.minisig", "server_list.json", "server_list.json", 10, []string{ - "RWSf0PYToIUJmDlsz21YOXvgQzHj9NSdyJUqEY5ZdfS9GepeXt3+JJRZ", pk[0], - }}, - {&verifyCreatePublicKeyError, "invalid allowed key", "server_list.json.minisig", "server_list.json", "server_list.json", 10, []string{"AAA"}}, + { + &verifyInvalidSignatureAlgorithmError, + "pure", + "server_list.json.pure.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + + { + nil, + "valid server_list", + "server_list.json.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + nil, + "TC no hashed", + "server_list.json.tc_nohashed.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + nil, + "TC later time", + "server_list.json.tc_latertime.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + &verifyWrongSigFilenameError, + "server_list TC file:organization_list", + "server_list.json.tc_orglist.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + &verifyWrongSigFilenameError, + "organization_list as server_list", + "organization_list.json.minisig", + "organization_list.json", + "server_list.json", + 10, + pk, + }, + { + &verifyWrongSigFilenameError, + "TC file:otherfile", + "server_list.json.tc_otherfile.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + &verifySigTimeEarlierError, + "TC no file", + "server_list.json.tc_nofile.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + &verifySigTimeEarlierError, + "TC no time", + "server_list.json.tc_notime.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + &verifySigTimeEarlierError, + "TC empty time", + "server_list.json.tc_emptytime.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + &verifyInvalidSignatureFormatError, + "TC empty file", + "server_list.json.tc_emptyfile.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + &verifyInvalidTrustedCommentError, + "TC random", + "server_list.json.tc_random.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + nil, + "large time", + "server_list.json.large_time.minisig", + "server_list.json", + "server_list.json", + 43e8, + pk, + }, + { + nil, + "lower min time", + "server_list.json.minisig", + "server_list.json", + "server_list.json", + 5, + pk, + }, + { + &verifySigTimeEarlierError, + "higher min time", + "server_list.json.minisig", + "server_list.json", + "server_list.json", + 11, + pk, + }, + + { + nil, + "valid organization_list", + "organization_list.json.minisig", + "organization_list.json", + "organization_list.json", + 10, + pk, + }, + { + &verifyWrongSigFilenameError, + "organization_list TC file:server_list", + "organization_list.json.tc_servlist.minisig", + "organization_list.json", + "organization_list.json", + 10, + pk, + }, + { + &verifyWrongSigFilenameError, + "server_list as organization_list", + "server_list.json.minisig", + "server_list.json", + "organization_list.json", + 10, + pk, + }, + + { + &verifyUnknownExpectedFilenameError, + "valid other_list", + "other_list.json.minisig", + "other_list.json", + "other_list.json", + 10, + pk, + }, + { + &verifyWrongSigFilenameError, + "other_list as server_list", + "other_list.json.minisig", + "other_list.json", + "server_list.json", + 10, + pk, + }, + + { + &verifyInvalidSignatureFormatError, + "invalid signature file", + "random.txt", + "server_list.json", + "server_list.json", + 10, + pk, + }, + { + &verifyInvalidSignatureFormatError, + "empty signature file", + "empty", + "server_list.json", + "server_list.json", + 10, + pk, + }, + + { + &verifyUnknownKeyError, + "wrong key", + "server_list.json.wrong_key.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + + { + &verifyInvalidSignatureAlgorithmError, + "forged pure signature", + "server_list.json.forged_pure.minisig", + "server_list.json.blake2b", + "server_list.json", + 10, + pk, + }, + { + &verifyInvalidSignatureError, + "forged key ID", + "server_list.json.forged_keyid.minisig", + "server_list.json", + "server_list.json", + 10, + pk, + }, + + { + &verifyUnknownKeyError, + "no allowed keys", + "server_list.json.minisig", + "server_list.json", + "server_list.json", + 10, + []string{}, + }, + { + nil, + "multiple allowed keys 1", + "server_list.json.minisig", + "server_list.json", + "server_list.json", + 10, + []string{ + pk[0], "RWSf0PYToIUJmDlsz21YOXvgQzHj9NSdyJUqEY5ZdfS9GepeXt3+JJRZ", + }, + }, + { + nil, + "multiple allowed keys 2", + "server_list.json.minisig", + "server_list.json", + "server_list.json", + 10, + []string{ + "RWSf0PYToIUJmDlsz21YOXvgQzHj9NSdyJUqEY5ZdfS9GepeXt3+JJRZ", pk[0], + }, + }, + { + &verifyCreatePublicKeyError, + "invalid allowed key", + "server_list.json.minisig", + "server_list.json", + "server_list.json", + 10, + []string{"AAA"}, + }, } // Cache file contents in map, mapping file names to contents @@ -117,8 +349,15 @@ func Test_verifyWithKeys(t *testing.T) { valid, err := verifyWithKeys(string(files[tt.signatureFile]), files[tt.jsonFile], tt.expectedFileName, tt.minSignTime, tt.allowedPks, forcePrehash) compareResults(t, valid, err, tt.expectedErr, func() string { - return fmt.Sprintf("verifyWithKeys(%q, %q, %q, %v, %v, %t)", - tt.signatureFile, tt.jsonFile, tt.expectedFileName, tt.minSignTime, tt.allowedPks, forcePrehash) + return fmt.Sprintf( + "verifyWithKeys(%q, %q, %q, %v, %v, %t)", + tt.signatureFile, + tt.jsonFile, + tt.expectedFileName, + tt.minSignTime, + tt.allowedPks, + forcePrehash, + ) }) }) } @@ -126,7 +365,13 @@ func Test_verifyWithKeys(t *testing.T) { // compareResults compares returned ret, err from a verify function with expected error code expected. // callStr is called to get the formatted parameters passed to the function. -func compareResults(t *testing.T, ret bool, err error, expectedErr interface{}, callStr func() string) { +func compareResults( + t *testing.T, + ret bool, + err error, + expectedErr interface{}, + callStr func() string, +) { // different error returned if expectedErr != nil && !errors.As(err, expectedErr) { t.Errorf("%v\nerror %T = %v, wantErr %T", callStr(), err, err, expectedErr) |
