From e544c6fa9e15e7277da79e2464243e90b2706b8c Mon Sep 17 00:00:00 2001 From: StevenWdV Date: Mon, 24 Jan 2022 14:59:25 +0100 Subject: Cleanup Added variables to Makefiles to specify custom exports/ directory; Split exception classes in Java & C#; Added more comments; Renamed library and Go package; Removed real (pure) tests; Added generate_lib.ps1 to generate import .lib for Windows (Swift); Moved built Go libraries to exports/lib/; Switch to hopefully faster Swift GitHub Action. --- wrappers/csharp/Discovery.cs | 86 +++++++++++++++++++++++++++----------------- 1 file changed, 54 insertions(+), 32 deletions(-) (limited to 'wrappers/csharp/Discovery.cs') diff --git a/wrappers/csharp/Discovery.cs b/wrappers/csharp/Discovery.cs index 183d94f..da4a6ea 100644 --- a/wrappers/csharp/Discovery.cs +++ b/wrappers/csharp/Discovery.cs @@ -1,8 +1,10 @@ using System; +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; +// Make InsecureTestingSetExtraKey visible to tests [assembly: InternalsVisibleTo("EduVpnCommonTests")] namespace EduVpnCommon @@ -11,12 +13,12 @@ namespace EduVpnCommon { /// /// Verifies the signature on the JSON server_list.json/organization_list.json file. - /// If the function returns the signature is valid for the given file type. + /// If the function returns, the signature is valid for the given file type. /// /// .minisig signature file contents. /// Signed .json file contents. /// The file type to be verified, one of "server_list.json" or "organization_list.json". - /// Minimum time for signature. Should be set to at least the time in a previously retrieved file. + /// Minimum time for signature. Should be set to at least the time of the previous signature. /// If expectedFileName is not one of the allowed values. /// If signature verification fails. public static void Verify( @@ -35,11 +37,20 @@ namespace EduVpnCommon (ulong) minSignTime.ToUnixTimeSeconds()); } - if (result != VerifyReturnCode.Ok) + switch (result) { - if (result == VerifyReturnCode.ErrUnknownExpectedFileName) - throw new ArgumentException("unknown name", nameof(expectedFileName)); - throw new VerifyException((VerifyErrorCode) result); + case VerifyReturnCode.Ok: + return; + case VerifyReturnCode.ErrUnknownExpectedFileName: + throw new ArgumentException("unknown expected file name", nameof(expectedFileName)); + case VerifyReturnCode.ErrInvalidSignature: + throw new InvalidSignatureException(); + case VerifyReturnCode.ErrInvalidSignatureUnknownKey: + throw new InvalidSignatureUnknownKeyException(); + case VerifyReturnCode.ErrTooOld: + throw new SignatureTooOldException(); + default: + throw new UnknownVerifyException((sbyte) result); } } @@ -50,13 +61,17 @@ namespace EduVpnCommon InsecureTestingSetExtraKey(keyHandle.Slice); } - const string VerifyLibName = "eduvpn_verify"; + const string LibName = "eduvpn_common"; - [DllImport(VerifyLibName)] + [DllImport(LibName)] static extern VerifyReturnCode Verify(GoSlice signatureFileContent, GoSlice signedJson, GoSlice expectedFileName, ulong minSignTime); - [DllImport(VerifyLibName)] static extern void InsecureTestingSetExtraKey(GoSlice keyStr); + [DllImport(LibName)] static extern void InsecureTestingSetExtraKey(GoSlice keyStr); + /// + /// Safe auto-disposing Go slice handle. + /// Non-copying alternative to `Marshal.AllocHGlobal` etc. + /// class GoSliceHandle : IDisposable { GCHandle gcHandle_; @@ -68,6 +83,7 @@ namespace EduVpnCommon GoSliceHandle(Array array, int offset, int count) { + Debug.Assert(offset <= array.Length && /*prevent overflow:*/ count <= array.Length && offset <= array.Length - count); gcHandle_ = GCHandle.Alloc(array, GCHandleType.Pinned); var elemSize = Marshal.SizeOf(array.GetType().GetElementType()!); slice_ = new GoSlice(gcHandle_.AddrOfPinnedObject() + offset * elemSize, count * elemSize); @@ -76,12 +92,14 @@ namespace EduVpnCommon public static GoSliceHandle FromArray(ArraySegment segment) where T : struct => new GoSliceHandle(segment.Array!, segment.Offset, segment.Count); + /// From string as UTF-8. public static GoSliceHandle FromString(string str) => FromArray(new ArraySegment(Encoding.UTF8.GetBytes(str))); public void Dispose() => gcHandle_.Free(); } + // C-compatible structure readonly struct GoSlice { readonly IntPtr data_; @@ -98,38 +116,42 @@ namespace EduVpnCommon } } - public class VerifyException : Exception + /// Verification failed, do not trust the file. + public abstract class VerifyException : Exception { - public VerifyErrorCode Code { get; } - - internal VerifyException(VerifyErrorCode code) : base(GetMessage(code)) => Code = code; + protected VerifyException(string message) : base(message) { } + } - static string GetMessage(VerifyErrorCode code) => code switch - { - VerifyErrorCode.ErrInvalidSignature => "invalid signature", - VerifyErrorCode.ErrInvalidSignatureUnknownKey => "invalid signature (unknown key)", - VerifyErrorCode.ErrTooOld => "replay of previous signature (rollback)", - _ => $"unknown verify error ({code})" - }; + /// Signature is invalid (for the expected file type). + public sealed class InvalidSignatureException : VerifyException + { + public InvalidSignatureException() : base("invalid signature") { } } - public enum VerifyErrorCode + /// Signature was created with an unknown key and has not been verified. + public sealed class InvalidSignatureUnknownKeyException : VerifyException { - /// Signature is invalid (for the expected file type). - ErrInvalidSignature = VerifyReturnCode.ErrUnknownExpectedFileName + 1, + public InvalidSignatureUnknownKeyException() : base("invalid signature (unknown key)") { } + } - /// Signature was created with an unknown key and has not been verified. - ErrInvalidSignatureUnknownKey, + /// Signature timestamp smaller than specified minimum signing time (rollback). + public sealed class SignatureTooOldException : VerifyException + { + public SignatureTooOldException() : base("replay of previous signature (rollback)") { } + } - /// Signature has a timestamp lower than the specified minimum signing time. - ErrTooOld + /// Other unknown error. + public sealed class UnknownVerifyException : VerifyException + { + public UnknownVerifyException(sbyte code) : base($"unknown verify error ({code})") => Debug.Assert(code != 0); } - enum VerifyReturnCode + enum VerifyReturnCode : sbyte { Ok, - ErrUnknownExpectedFileName - - //... + ErrUnknownExpectedFileName, + ErrInvalidSignature, + ErrInvalidSignatureUnknownKey, + ErrTooOld } -} \ No newline at end of file +} -- cgit v1.2.3