summaryrefslogtreecommitdiff
path: root/verify.go
diff options
context:
space:
mode:
authorStevenWdV <stevenwdv@gmail.com>2021-11-20 18:09:09 +0100
committerStevenWdV <stevenwdv@gmail.com>2021-11-22 12:37:33 +0100
commit8878d8705f0b0fcddb3979194340ca39df897580 (patch)
tree6c920d0b9d40584dfe6bf7e5b2e865acff72e72f /verify.go
parentb8d368b93479233a8ecbeba3daf4b10bee8f0a4a (diff)
Add C bindings and a C# wrapper
Diffstat (limited to 'verify.go')
-rw-r--r--verify.go129
1 files changed, 97 insertions, 32 deletions
diff --git a/verify.go b/verify.go
index 89a3d74..5cca4d0 100644
--- a/verify.go
+++ b/verify.go
@@ -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}
+}