diff options
| author | StevenWdV <stevenwdv@gmail.com> | 2021-11-20 18:09:09 +0100 |
|---|---|---|
| committer | StevenWdV <stevenwdv@gmail.com> | 2021-11-22 12:37:33 +0100 |
| commit | 8878d8705f0b0fcddb3979194340ca39df897580 (patch) | |
| tree | 6c920d0b9d40584dfe6bf7e5b2e865acff72e72f /verify.go | |
| parent | b8d368b93479233a8ecbeba3daf4b10bee8f0a4a (diff) | |
Add C bindings and a C# wrapper
Diffstat (limited to 'verify.go')
| -rw-r--r-- | verify.go | 129 |
1 files changed, 97 insertions, 32 deletions
@@ -3,6 +3,7 @@ package eduvpn_verify import ( "fmt" "github.com/jedisct1/go-minisign" + "os" ) // Verify verifies the signature (.minisig file format) on signedJson. @@ -11,7 +12,7 @@ import ( // minSign must be set to the minimum UNIX timestamp (without milliseconds) for the file version. // This value should not be smaller than the time on the previous document verified. // -// The return value will either be (true, nil) for a valid signature or (false, err) otherwise. +// 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) (bool, error) { @@ -19,11 +20,51 @@ func Verify(signatureFileContent string, signedJson []byte, expectedFileName str "RWRtBSX1alxyGX+Xn3LuZnWUT0w//B6EmTJvgaAxBMYzlQeI+jdrO6KF", // fkooman@tuxed.net, kolla@uninett.no "RWQKqtqvd0R7rUDp0rWzbtYPA3towPWcLDCl7eY9pBMMI/ohCmrS0WiM", // RoSp } + if extraKey != "" { + keyStrs = append(keyStrs, extraKey) + _, err := fmt.Fprintf(os.Stderr, "INSECURE TEST MODE ENABLED WITH KEY %q\n", extraKey) + if err != nil { + panic(err) + } + } valid, err := verifyWithKeys(signatureFileContent, signedJson, expectedFileName, minSignTime, keyStrs) - if err != nil && err.(VerifyError).Code == ErrInvalidPublicKey { - panic(err) // This should not happen + if err != nil { + if err.(detailedVerifyError).Code == errInvalidPublicKey { + panic(err) // This should not happen unless keyStrs has an invalid key + } + return valid, err.(detailedVerifyError).ToVerifyError() } - return valid, err + return valid, nil +} + +// Extra allowed key for testing +var extraKey = "" + +// InsecureTestingSetExtraKey adds an extra allowed key for verification with Verify. +// ONLY USE FOR TESTING. Probably not thread-safe. Do not call in parallel to Verify. +func InsecureTestingSetExtraKey(keyString string) { + extraKey = keyString +} + +type VerifyErrorCode int + +const ( + ErrUnknownExpectedFileName VerifyErrorCode = iota + 1 + ErrInvalidSignature + ErrInvalidSignatureUnknownKey + ErrTooOld +) + +type VerifyError struct { + Code VerifyErrorCode + Detailed detailedVerifyError +} + +func (err VerifyError) Error() string { + return err.Detailed.Error() +} +func (err VerifyError) Unwrap() error { + return err.Detailed } // verifyWithKeys verifies the Minisign signature in signatureFileContent (minisig file format) over the server_list/organization_list JSON in signedJson. @@ -34,29 +75,28 @@ func Verify(signatureFileContent string, signedJson []byte, expectedFileName str // 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, err) on failure. +// The return value will either be (true, nil) on success or (false, detailedVerifyError) on failure. func verifyWithKeys(signatureFileContent string, signedJson []byte, expectedFileName string, minSignTime uint64, allowedPublicKeys []string) (bool, error) { switch expectedFileName { case "server_list.json", "organization_list.json": break default: - return false, VerifyError{ErrUnknownExpectedFileName, - fmt.Sprintf("invalid expected file name (%v)", expectedFileName), nil} + return false, detailedVerifyError{errUnknownExpectedFileName, "invalid expected file name", nil} } sig, err := minisign.DecodeSignature(signatureFileContent) if err != nil { - return false, VerifyError{ErrInvalidSignatureFormat, "invalid signature format", err} + return false, detailedVerifyError{errInvalidSignatureFormat, "invalid signature format", err} } if sig.SignatureAlgorithm != [2]byte{'E', 'D'} { - return false, VerifyError{ErrInvalidSignatureAlgorithm, "BLAKE2b-prehashed EdDSA signature required", nil} + return false, detailedVerifyError{errInvalidSignatureAlgorithm, "BLAKE2b-prehashed EdDSA signature required", nil} } for _, keyStr := range allowedPublicKeys { key, err := minisign.NewPublicKey(keyStr) if err != nil { - return false, VerifyError{ErrInvalidPublicKey, "internal error: could not create public key", err} + return false, detailedVerifyError{errInvalidPublicKey, "internal error: could not create public key", err} } if sig.KeyId != key.KeyId { @@ -65,7 +105,7 @@ func verifyWithKeys(signatureFileContent string, signedJson []byte, expectedFile valid, err := key.Verify(signedJson, sig) if !valid { - return false, VerifyError{ErrInvalidSignature, "invalid signature", err} + return false, detailedVerifyError{errInvalidSignature, "invalid signature", err} } var signTime uint64 @@ -73,49 +113,74 @@ func verifyWithKeys(signatureFileContent string, signedJson []byte, expectedFile // sigFileName cannot have spaces _, err = fmt.Sscanf(sig.TrustedComment, "trusted comment: timestamp:%d\tfile:%s", &signTime, &sigFileName) if err != nil { - return false, VerifyError{ErrInvalidTrustedComment, - fmt.Sprintf("failed to interpret trusted comment (%q)", sig.TrustedComment), err} + return false, detailedVerifyError{errInvalidTrustedComment, "failed to interpret trusted comment", err} } if sigFileName != expectedFileName { - return false, VerifyError{ErrWrongFileName, - fmt.Sprintf("signature was on file %q instead of expected %q", sigFileName, expectedFileName), nil} + return false, detailedVerifyError{errWrongFileName, "signature was created for wrong file", nil} } if signTime < minSignTime { - return false, VerifyError{ErrTooOld, - fmt.Sprintf("signature was created at %v < minimum time (%v)", signTime, minSignTime), nil} + return false, detailedVerifyError{errTooOld, "signature was created a time earlier than the minimum time specified", nil} } return true, nil } - return false, VerifyError{ErrWrongKey, "signature was created with an unknown key", nil} + return false, detailedVerifyError{errWrongKey, "signature was created with unknown key", nil} } -type VerifyErrCode int +type detailedVerifyErrorCode int const ( - ErrUnknownExpectedFileName VerifyErrCode = iota - ErrInvalidSignatureFormat - ErrInvalidSignatureAlgorithm - ErrInvalidPublicKey - ErrInvalidSignature - ErrInvalidTrustedComment - ErrWrongFileName - ErrTooOld - ErrWrongKey + errUnknownExpectedFileName detailedVerifyErrorCode = iota + 1 + errInvalidSignatureFormat + errInvalidSignatureAlgorithm + errInvalidPublicKey + errInvalidSignature + errInvalidTrustedComment + errWrongFileName + errTooOld + errWrongKey ) -type VerifyError struct { - Code VerifyErrCode +func (code detailedVerifyErrorCode) ToVerifyErrorCode() VerifyErrorCode { + switch code { + case errUnknownExpectedFileName: + return ErrUnknownExpectedFileName + case errInvalidSignatureFormat: + return ErrInvalidSignature + case errInvalidSignatureAlgorithm: + return ErrInvalidSignature + case errInvalidPublicKey: + panic("errInvalidPublicKey cannot be converted to VerifyErrorCode") + case errInvalidSignature: + return ErrInvalidSignature + case errInvalidTrustedComment: + return ErrInvalidSignature + case errWrongFileName: + return ErrInvalidSignature + case errTooOld: + return ErrTooOld + case errWrongKey: + return ErrInvalidSignatureUnknownKey + } + panic("invalid detailedVerifyErrorCode") +} + +type detailedVerifyError struct { + Code detailedVerifyErrorCode Message string Cause error } -func (err VerifyError) Error() string { +func (err detailedVerifyError) Error() string { return err.Message } -func (err VerifyError) Unwrap() error { +func (err detailedVerifyError) Unwrap() error { return err.Cause } + +func (err detailedVerifyError) ToVerifyError() VerifyError { + return VerifyError{err.Code.ToVerifyErrorCode(), err} +} |
