diff options
| author | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-05-02 14:34:35 +0200 |
|---|---|---|
| committer | jwijenbergh <jeroenwijenbergh@protonmail.com> | 2022-05-02 14:34:35 +0200 |
| commit | 466450f0c47bdc614e66326d90e5fc6fb56ae732 (patch) | |
| tree | a01518a58d50d2f8449d37dadecc40e35c9f1fe1 /internal/verify.go | |
| parent | a2a8efdcaad3d9b1852b1367a7cd7e8c5860cecf (diff) | |
Refactor: Wrap most errors in a custom type
Diffstat (limited to 'internal/verify.go')
| -rw-r--r-- | internal/verify.go | 154 |
1 files changed, 77 insertions, 77 deletions
diff --git a/internal/verify.go b/internal/verify.go index 9128777..713e4d7 100644 --- a/internal/verify.go +++ b/internal/verify.go @@ -58,13 +58,81 @@ func InsecureTestingSetExtraKey(keyString string) { extraKey = keyString } +// verifyWithKeys verifies the Minisign signature in signatureFileContent (minisig file format) over the server_list/organization_list JSON in signedJson. +// +// Verification is performed using a matching key in allowedPublicKeys. +// The signature is checked to be a Ed25519 Minisign (optionally Ed25519 Blake2b-512 prehashed, see forcePrehash) signature with a valid trusted comment. +// The file type that is verified is indicated by expectedFileName, which must be one of "server_list.json"/"organization_list.json". +// The trusted comment is checked to be of the form "timestamp:<timestamp>\tfile:<expectedFileName>", optionally suffixed by something, e.g. "\thashed". +// The signature is checked to have a timestamp with a value of at least minSignTime, which is a UNIX timestamp without milliseconds. +// +// The return value will either be (true, nil) on success or (false, detailedVerifyError) on failure. +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"} + } + + sig, err := minisign.DecodeSignature(signatureFileContent) + if err != nil { + return false, &VerifyInvalidSignatureFormatError{Err: err} + } + + // 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)"} + } + + // Find allowed key used for signature + for _, keyStr := range allowedPublicKeys { + key, err := minisign.NewPublicKey(keyStr) + if err != nil { + // Should only happen if Verify is wrong or extraKey is invalid + return false, &VerifyCreatePublicKeyError{PublicKey: keyStr, Err: err} + } + + if sig.KeyId != key.KeyId { + continue // Wrong key + } + + valid, err := key.Verify(signedJson, sig) + if !valid { + return false, &VerifyInvalidSignatureError{Err: err} + } + + // Parse trusted comment + var signTime uint64 + var sigFileName string + // sigFileName cannot have spaces + _, err = fmt.Sscanf(sig.TrustedComment, "trusted comment: timestamp:%d\tfile:%s", &signTime, &sigFileName) + if err != nil { + return false, &VerifyInvalidTrustedCommentError{TrustedComment: sig.TrustedComment, Err: err} + } + + if sigFileName != filename { + return false, &VerifyWrongSigFilenameError{Filename: filename, SigFilename: sigFileName} + } + + if signTime < minSignTime { + return false, &VerifySigTimeEarlierError{SigTime: signTime, MinSigTime: minSignTime} + } + + return true, nil + } + + // No matching allowed key found + return false, &VerifyUnknownKeyError{Filename: filename} +} + type VerifyUnknownExpectedFilenameError struct { Filename string Expected string } func (e *VerifyUnknownExpectedFilenameError) Error() string { - return fmt.Sprintf("invalid filename %s, expected %s", e.Filename, e.Expected) + return fmt.Sprintf("invalid filename: %s, expected: %s", e.Filename, e.Expected) } type VerifyInvalidSignatureFormatError struct { @@ -72,7 +140,7 @@ type VerifyInvalidSignatureFormatError struct { } func (e *VerifyInvalidSignatureFormatError) Error() string { - return fmt.Sprintf("invalid signature format, error %v", e.Err) + return fmt.Sprintf("invalid signature format with error: %v", e.Err) } type VerifyInvalidSignatureAlgorithmError struct { @@ -81,7 +149,7 @@ 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 { @@ -90,7 +158,7 @@ type VerifyCreatePublicKeyError struct { } func (e *VerifyCreatePublicKeyError) Error() string { - return fmt.Sprintf("failed to create public key %s with error %v", e.PublicKey, e.Err) + return fmt.Sprintf("failed to create public key: %s with error: %v", e.PublicKey, e.Err) } type VerifyInvalidSignatureError struct { @@ -98,7 +166,7 @@ type VerifyInvalidSignatureError struct { } func (e *VerifyInvalidSignatureError) Error() string { - return fmt.Sprintf("invalid signature with error %v", e.Err) + return fmt.Sprintf("invalid signature with error: %v", e.Err) } type VerifyInvalidTrustedCommentError struct { @@ -107,7 +175,7 @@ type VerifyInvalidTrustedCommentError struct { } func (e *VerifyInvalidTrustedCommentError) Error() string { - return fmt.Sprintf("invalid trusted comment %s with error %v", e.TrustedComment, e.Err) + return fmt.Sprintf("invalid trusted comment: %s with error: %v", e.TrustedComment, e.Err) } type VerifyWrongSigFilenameError struct { @@ -116,7 +184,7 @@ 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 { @@ -125,7 +193,7 @@ type VerifySigTimeEarlierError struct { } func (e *VerifySigTimeEarlierError) Error() string { - return fmt.Sprintf("Sign time %d is earlier than sign time %d", e.SigTime, e.MinSigTime) + return fmt.Sprintf("Sign time: %d is earlier than sign time: %d", e.SigTime, e.MinSigTime) } type VerifyUnknownKeyError struct { @@ -133,73 +201,5 @@ type VerifyUnknownKeyError struct { } func (e *VerifyUnknownKeyError) Error() string { - return fmt.Sprintf("signature for filename %s was created with an unknown key", e.Filename) -} - -// verifyWithKeys verifies the Minisign signature in signatureFileContent (minisig file format) over the server_list/organization_list JSON in signedJson. -// -// Verification is performed using a matching key in allowedPublicKeys. -// The signature is checked to be a Ed25519 Minisign (optionally Ed25519 Blake2b-512 prehashed, see forcePrehash) signature with a valid trusted comment. -// The file type that is verified is indicated by expectedFileName, which must be one of "server_list.json"/"organization_list.json". -// The trusted comment is checked to be of the form "timestamp:<timestamp>\tfile:<expectedFileName>", optionally suffixed by something, e.g. "\thashed". -// The signature is checked to have a timestamp with a value of at least minSignTime, which is a UNIX timestamp without milliseconds. -// -// The return value will either be (true, nil) on success or (false, detailedVerifyError) on failure. -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"} - } - - sig, err := minisign.DecodeSignature(signatureFileContent) - if err != nil { - return false, &VerifyInvalidSignatureFormatError{Err: err} - } - - // 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)"} - } - - // Find allowed key used for signature - for _, keyStr := range allowedPublicKeys { - key, err := minisign.NewPublicKey(keyStr) - if err != nil { - // Should only happen if Verify is wrong or extraKey is invalid - return false, &VerifyCreatePublicKeyError{PublicKey: keyStr, Err: err} - } - - if sig.KeyId != key.KeyId { - continue // Wrong key - } - - valid, err := key.Verify(signedJson, sig) - if !valid { - return false, &VerifyInvalidSignatureError{Err: err} - } - - // Parse trusted comment - var signTime uint64 - var sigFileName string - // sigFileName cannot have spaces - _, err = fmt.Sscanf(sig.TrustedComment, "trusted comment: timestamp:%d\tfile:%s", &signTime, &sigFileName) - if err != nil { - return false, &VerifyInvalidTrustedCommentError{TrustedComment: sig.TrustedComment, Err: err} - } - - if sigFileName != filename { - return false, &VerifyWrongSigFilenameError{Filename: filename, SigFilename: sigFileName} - } - - if signTime < minSignTime { - return false, &VerifySigTimeEarlierError{SigTime: signTime, MinSigTime: minSignTime} - } - - return true, nil - } - - // No matching allowed key found - return false, &VerifyUnknownKeyError{Filename: filename} + return fmt.Sprintf("signature for filename: %s was created with an unknown key", e.Filename) } |
