예제 #1
0
        static void Main(string[] args)
        {
            Regex sign_matcher      = new Regex(@"--sign=.*", RegexOptions.Compiled | RegexOptions.ECMAScript);
            Regex key_matcher       = new Regex(@"--key=.*", RegexOptions.Compiled | RegexOptions.ECMAScript);
            Regex version_matcher   = new Regex(@"--version=.*", RegexOptions.Compiled | RegexOptions.ECMAScript);
            Regex verify_matcher    = new Regex(@"--verify=.*", RegexOptions.Compiled | RegexOptions.ECMAScript);
            Regex signature_matcher = new Regex(@"--signature=.*", RegexOptions.Compiled | RegexOptions.ECMAScript);

            if (args.Any(s => s == "--help"))
            {
                string executable_name = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) switch
                {
                    true => "gms.exe",
                    _ => "./gms"
                };
                Console.WriteLine("GmodNetModuleSigner 1.0.0 by Gleb Krasilich. https://github.com/GlebChili/GmodNetModuleSigner.");
                Console.WriteLine("Usage: " + executable_name + " [FLAG1] [FLAG2] ...\n");
                Console.WriteLine("Flags:\n");
                Console.WriteLine("--help: usage help\n");
                Console.WriteLine("--generate-key: Generate new private and public keys pair and save it as private.modulekey file.\n");
                Console.WriteLine("--sign=[module_to_sign_path]: sign given file (relative or absolute path). Must be used wtih --key flag " +
                                  "and --version flag. Output: signature.modulesign file.\n");
                Console.WriteLine("--key=[path_to_key]: Use following key for sign and verification process (relative or absolute path).\n");
                Console.WriteLine("--version=[module_version]: Explicitly specify module version to add to *.modulekey file.\n");
                Console.WriteLine("--verify=[module_to_verify_path]: Verify signature of the module. Must be used with --key and --signature flags.");
                Console.WriteLine("--signature=[path_to_the_signature_file]: Signature for the verification process.");
            }
            else if (args.Any(s => s == "--generate-key"))
            {
                Console.WriteLine("Generating new key pair");

                Task <TextKeyPair> future_key = Task <TextKeyPair> .Factory.StartNew(GenerateKey, TaskCreationOptions.LongRunning);

                int tick_counter = 0;

                while (!future_key.IsCompleted)
                {
                    tick_counter++;
                    tick_counter = tick_counter % 1000000000;

                    if (tick_counter == 0)
                    {
                        Console.Write(".");
                    }
                }

                Console.Write("\n");

                TextKeyPair result = future_key.Result;

                byte[] key_json = JsonSerializer.SerializeToUtf8Bytes <TextKeyPair>(result, new JsonSerializerOptions {
                    WriteIndented = true
                });

                File.WriteAllBytes("private.modulekey", key_json);

                Console.WriteLine("Key pair generated and saved as private.modulekey file. KEEP YOUR SECRET KEY SAFE!");
            }
            else if (args.Any(s => sign_matcher.IsMatch(s)))
            {
                Console.WriteLine("Starting sign process...");

                string sign_flag = args.First(s => sign_matcher.IsMatch(s));
                string sign_path;

                try
                {
                    sign_path = sign_flag.Split("=")[1];
                }
                catch
                {
                    Console.WriteLine("Path for file to sign is empty or invalid. Try again.");
                    return;
                }

                string key_flag = args.First(s => key_matcher.IsMatch(s));
                string key_path;
                if (key_flag == null || key_flag == String.Empty)
                {
                    Console.WriteLine("The --key=[path_to_key] flag is missing. Try again.");
                    return;
                }

                try
                {
                    key_path = key_flag.Split("=")[1];
                }
                catch
                {
                    Console.WriteLine("Key file path is empty or invalid. Try again.");
                    return;
                }

                byte[] key_blob;
                try
                {
                    key_blob = File.ReadAllBytes(key_path);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to read key file: " + e.GetType().ToString() + " " + e.Message + ". Try again.");
                    return;
                }

                TextKeyPair key_pair;
                try
                {
                    key_pair = JsonSerializer.Deserialize <TextKeyPair>(key_blob);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to parse key file: " + e.GetType().ToString() + " " + e.Message + ". Try again.");
                    return;
                }

                if (key_pair.PrivateKey == null || key_pair.PrivateKey == String.Empty)
                {
                    Console.WriteLine("The key file contains no secret key. Try again.");
                    return;
                }

                string version_flag = args.First(s => version_matcher.IsMatch(s));
                if (version_flag == null || version_flag == String.Empty)
                {
                    Console.WriteLine("--version flag is missing. Try again.");
                    return;
                }

                string version_name;
                try
                {
                    version_name = version_flag.Split("=")[1];
                }
                catch
                {
                    Console.WriteLine("The vesrsion is empty or invalid. Try again.");
                    return;
                }

                Sha512 sha512 = HashAlgorithm.Sha512;

                byte[] file_blob;
                try
                {
                    file_blob = File.ReadAllBytes(sign_path);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to read file to sign: " + e.GetType().ToString() + " " + e.Message + ". Try again.");
                    return;
                }

                byte[] file_hash = sha512.Hash(file_blob);

                file_hash = file_hash.Concat(Encoding.UTF8.GetBytes(version_name)).ToArray();

                byte[] final_hash = sha512.Hash(file_hash);

                byte[] raw_private_key = HexToBytes(key_pair.PrivateKey);

                Ed25519 ed25519 = SignatureAlgorithm.Ed25519;

                Key private_key;

                try
                {
                    private_key = Key.Import(ed25519, raw_private_key, KeyBlobFormat.RawPrivateKey);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to import private key: " + e.GetType() + " " + e.Message + ". Try again.");
                    return;
                }

                byte[] final_signature = ed25519.Sign(private_key, final_hash);

                ModuleSignature sign_struct = new ModuleSignature
                {
                    Version   = version_name,
                    Signature = BitConverter.ToString(final_signature).Replace("-", "")
                };

                byte[] sign_to_write = JsonSerializer.SerializeToUtf8Bytes <ModuleSignature>(sign_struct, new JsonSerializerOptions {
                    WriteIndented = true
                });

                File.WriteAllBytes("signature.modulesign", sign_to_write);

                Console.WriteLine("File was successfully signed.");
            }
            else if (args.Any(s => verify_matcher.IsMatch(s)))
            {
                Console.WriteLine("Starting verification process...");

                string verify_flag = args.First(s => verify_matcher.IsMatch(s));

                string verify_path;
                try
                {
                    verify_path = verify_flag.Split("=")[1];
                }
                catch
                {
                    Console.WriteLine("Path for the file to verify is empty or invalid. Try again.");
                    return;
                }

                string key_flag = args.First(s => key_matcher.IsMatch(s));
                string key_path;
                if (key_flag == null || key_flag == String.Empty)
                {
                    Console.WriteLine("The --key=[path_to_key] flag is missing. Try again.");
                    return;
                }

                try
                {
                    key_path = key_flag.Split("=")[1];
                }
                catch
                {
                    Console.WriteLine("Key file path is empty or invalid. Try again.");
                    return;
                }

                string signature_flag = args.First(s => signature_matcher.IsMatch(s));
                string signature_path;
                if (signature_flag == null || signature_flag == String.Empty)
                {
                    Console.WriteLine("-signature=[path_to_the_signature] flag is missing. Try again.");
                    return;
                }
                try
                {
                    signature_path = signature_flag.Split("=")[1];
                }
                catch
                {
                    Console.WriteLine("Signature path is empty or invalid. Try again.");
                    return;
                }

                byte[] file_blob;
                try
                {
                    file_blob = File.ReadAllBytes(verify_path);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to read the module to verify: " + e.GetType().ToString() + " " + e.Message + ". Try again.");
                    return;
                }

                byte[] key_blob;
                try
                {
                    key_blob = File.ReadAllBytes(key_path);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to read key: " + e.GetType().ToString() + " " + e.Message + ". Try again.");
                    return;
                }

                byte[] signature_blob;
                try
                {
                    signature_blob = File.ReadAllBytes(signature_path);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to read signature: " + e.GetType() + " " + e.Message + ". Try again.");
                    return;
                }

                TextKeyPair key_pair;
                try
                {
                    key_pair = JsonSerializer.Deserialize <TextKeyPair>(key_blob);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to parse key file: " + e.GetType().ToString() + " " + e.Message + ". Try again.");
                    return;
                }

                if (key_pair.PublicKey == null || key_pair.PublicKey == String.Empty)
                {
                    Console.WriteLine("Public key is empty or invalid. Try again.");
                    return;
                }

                ModuleSignature signature;
                try
                {
                    signature = JsonSerializer.Deserialize <ModuleSignature>(signature_blob);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to parse signature file: " + e.GetType().ToString() + e.Message + ". Try again.");
                    return;
                }

                Sha512 sha512 = HashAlgorithm.Sha512;

                byte[] file_hash = sha512.Hash(file_blob);

                file_hash = file_hash.Concat(Encoding.UTF8.GetBytes(signature.Version)).ToArray();

                byte[] final_hash = sha512.Hash(file_hash);

                Ed25519 ed25519 = SignatureAlgorithm.Ed25519;

                PublicKey public_key;
                try
                {
                    byte[] raw_public_key = HexToBytes(key_pair.PublicKey);
                    public_key = PublicKey.Import(ed25519, raw_public_key, KeyBlobFormat.RawPublicKey);
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to parse public key: " + e.GetType().ToString() + " " + e.Message + ". Try again.");
                    return;
                }

                try
                {
                    bool is_valid = ed25519.Verify(public_key, final_hash, HexToBytes(signature.Signature));
                    if (is_valid)
                    {
                        Console.WriteLine("Signature is valid.");
                    }
                    else
                    {
                        Console.WriteLine("Signature is NOT valid.");
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("Unable to verify signature: " + e.GetType().ToString() + " " + e.Message + ". Try again.");
                    return;
                }
            }
            else
            {
                Console.WriteLine("GmodNetModuleSigner 1.0.0 by Gleb Krasilich. https://github.com/GlebChili/GmodNetModuleSigner.");
                Console.WriteLine("Use --help flag for usage help.");
            }
        }
        internal override void PreResolve(ModuleDefinition m)
        {
            if (m.RefinementBaseRoot != null) {
            RefinedSig = m.RefinementBaseRoot.Signature;

            if (RefinedSig.ModuleDef != null) {
              if (RefinedSig.ModuleDef.IsProtected) {
            reporter.Error(MessageSource.RefinementTransformer, m.RefinementBaseName, "module ({0}) named as a refinement base is marked protected and cannot be refined", m.RefinementBaseName.val);
              }

              m.RefinementBase = RefinedSig.ModuleDef;
              if (m.IsExclusiveRefinement) {
            if (null == m.RefinementBase.ExclusiveRefinement) {
              m.RefinementBase.ExclusiveRefinement = m;
            } else {
              reporter.Error(MessageSource.RefinementTransformer,
                  m.tok,
                  "no more than one exclusive refinement may exist for a given module.");
            }
              }
              // check that the openess in the imports between refinement and its base matches
              List<TopLevelDecl> declarations = m.TopLevelDecls;
              List<TopLevelDecl> baseDeclarations = m.RefinementBase.TopLevelDecls;
              foreach (var im in declarations) {
            if (im is ModuleDecl) {
              ModuleDecl mdecl = (ModuleDecl)im;
              //find the matching import from the base
              // TODO: this is a terribly slow algorithm; use the symbol table instead
              foreach (var bim in baseDeclarations) {
                if (bim is ModuleDecl && ((ModuleDecl)bim).Name.Equals(mdecl.Name)) {
                  if (mdecl.Opened != ((ModuleDecl)bim).Opened) {
                    string message = mdecl.Opened ?
                      "{0} in {1} cannot be imported with \"opened\" because it does not match the corresponding import in the refinement base {2} " :
                      "{0} in {1} must be imported with \"opened\"  to match the corresponding import in its refinement base {2}.";
                    reporter.Error(MessageSource.RefinementTransformer, m.tok, message, im.Name, m.Name, m.RefinementBase.Name);
                  }
                  break;
                }
                break;
              }
            }
              }
              PreResolveWorker(m);

            } else {
              reporter.Error(MessageSource.RefinementTransformer, m.RefinementBaseName, "module ({0}) named as refinement base does not exist", m.RefinementBaseName.val);
            }
              }
        }
예제 #3
0
    public bool CheckIsRefinement(ModuleSignature derived, ModuleSignature original) {
      // Check refinement by construction.
      var derivedPointer = derived;
      while (derivedPointer != null) {
        if (derivedPointer == original)
          return true;
        derivedPointer = derivedPointer.Refines;
      }
      // Check structural refinement. Note this involves several checks.
      // First, we need to know if the two modules are signature compatible;
      // this is determined immediately as it is necessary for determining
      // whether resolution will succeed. This involves checking classes, datatypes,
      // type declarations, and nested modules. 
      // Second, we need to determine whether the specifications will be compatible
      // (i.e. substitutable), by translating to Boogie.

      var errorCount = reporter.Count(ErrorLevel.Error);
      foreach (var kv in original.TopLevels) {
        var d = kv.Value;
        TopLevelDecl nw;
        if (derived.TopLevels.TryGetValue(kv.Key, out nw)) {
          if (d is ModuleDecl) {
            if (!(nw is ModuleDecl)) {
              reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name);
            } else {
              CheckIsRefinement(((ModuleDecl)nw).Signature, ((ModuleDecl)d).Signature);
            }
          } else if (d is OpaqueTypeDecl) {
            if (nw is ModuleDecl) {
              reporter.Error(MessageSource.RefinementTransformer, nw, "a module ({0}) must refine another module", nw.Name);
            } else {
              bool dDemandsEqualitySupport = ((OpaqueTypeDecl)d).MustSupportEquality;
              if (nw is OpaqueTypeDecl) {
                if (dDemandsEqualitySupport != ((OpaqueTypeDecl)nw).MustSupportEquality) {
                  reporter.Error(MessageSource.RefinementTransformer, nw, "type declaration '{0}' is not allowed to change the requirement of supporting equality", nw.Name);
                }
              } else if (dDemandsEqualitySupport) {
                if (nw is ClassDecl) {
                  // fine, as long as "nw" does not take any type parameters
                  if (nw.TypeArgs.Count != 0) {
                    reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a class that takes type parameters", nw.Name);
                  }
                } else if (nw is CoDatatypeDecl) {
                  reporter.Error(MessageSource.RefinementTransformer, nw, "a type declaration that requires equality support cannot be replaced by a codatatype");
                } else {
                  Contract.Assert(nw is IndDatatypeDecl);
                  if (nw.TypeArgs.Count != 0) {
                    reporter.Error(MessageSource.RefinementTransformer, nw, "opaque type '{0}' is not allowed to be replaced by a datatype that takes type parameters", nw.Name);
                  } else {
                    var udt = new UserDefinedType(nw.tok, nw.Name, nw, new List<Type>());
                    if (!(udt.SupportsEquality)) {
                      reporter.Error(MessageSource.RefinementTransformer, nw.tok, "datatype '{0}' is used to refine an opaque type with equality support, but '{0}' does not support equality", nw.Name);
                    }
                  }
                }
              }
            }
          } else if (d is DatatypeDecl) {
            if (nw is DatatypeDecl) {
              if (d is IndDatatypeDecl && !(nw is IndDatatypeDecl)) {
                reporter.Error(MessageSource.RefinementTransformer, nw, "a datatype ({0}) must be replaced by a datatype, not a codatatype", d.Name);
              } else if (d is CoDatatypeDecl && !(nw is CoDatatypeDecl)) {
                reporter.Error(MessageSource.RefinementTransformer, nw, "a codatatype ({0}) must be replaced by a codatatype, not a datatype", d.Name);
              }
              // check constructors, formals, etc.
              CheckDatatypesAreRefinements((DatatypeDecl)d, (DatatypeDecl)nw);
            } else {
              reporter.Error(MessageSource.RefinementTransformer, nw, "a {0} ({1}) must be refined by a {0}", d is IndDatatypeDecl ? "datatype" : "codatatype", d.Name);
            }
          } else if (d is ClassDecl) {
            if (!(nw is ClassDecl)) {
              reporter.Error(MessageSource.RefinementTransformer, nw, "a class declaration ({0}) must be refined by another class declaration", nw.Name);
            } else {
              CheckClassesAreRefinements((ClassDecl)nw, (ClassDecl)d);
            }
          } else {
            Contract.Assert(false); throw new cce.UnreachableException(); // unexpected toplevel
          }
        } else {
          reporter.Error(MessageSource.RefinementTransformer, d, "declaration {0} must have a matching declaration in the refining module", d.Name);
        }
      }
      return errorCount == reporter.Count(ErrorLevel.Error);
    }
        void PreResolveWorker(ModuleDefinition m)
        {
            Contract.Requires(m != null);

              if (m.RefinementBase == null) return;

              if (moduleUnderConstruction != null) {
            postTasks.Clear();
              }
              moduleUnderConstruction = m;
              refinementCloner = new RefinementCloner(moduleUnderConstruction);
              var prev = m.RefinementBase;

              //copy the signature, including its opened imports
              refinedSigOpened = Resolver.MergeSignature(new ModuleSignature(), RefinedSig);
              Resolver.ResolveOpenedImports(refinedSigOpened, m.RefinementBase, false, null);

              // Create a simple name-to-decl dictionary.  Ignore any duplicates at this time.
              var declaredNames = new Dictionary<string, int>();
              for (int i = 0; i < m.TopLevelDecls.Count; i++) {
            var d = m.TopLevelDecls[i];
            if (!declaredNames.ContainsKey(d.Name)) {
              declaredNames.Add(d.Name, i);
            }

            // TODO: This is more restrictive than is necessary,
            // it would be possible to disambiguate these, but it seems like
            // a lot of work for not much gain

            if (refinedSigOpened.TopLevels.ContainsKey(d.Name) &&
              !RefinedSig.TopLevels.ContainsKey(d.Name)) {
              var decl = Resolver.AmbiguousTopLevelDecl.Create(m, d, refinedSigOpened.TopLevels[d.Name]);

              if (decl is Resolver.AmbiguousTopLevelDecl) {
            reporter.Error(MessageSource.RefinementTransformer, d.tok, "Base module {0} imports {1} from an opened import, so it cannot be overridden. Give this declaration a unique name to disambiguate.", prev.Name, d.Name);
              }
            }
              }

              // Merge the declarations of prev into the declarations of m
              List<string> processedDecl = new List<string>();
              foreach (var d in prev.TopLevelDecls) {
            int index;
            processedDecl.Add(d.Name);
            if (!declaredNames.TryGetValue(d.Name, out index)) {
              m.TopLevelDecls.Add(refinementCloner.CloneDeclaration(d, m));
            } else {
              var nw = m.TopLevelDecls[index];
              MergeTopLevelDecls(m, nw, d, index);
            }
              }

              // Merge the imports of prev
              var prevTopLevelDecls = RefinedSig.TopLevels.Values;
              foreach (var d in prevTopLevelDecls) {
            int index;
            if (!processedDecl.Contains(d.Name) && (declaredNames.TryGetValue(d.Name, out index))) {
              // if it is redefined, we need to merge them.
              var nw = m.TopLevelDecls[index];
              MergeTopLevelDecls(m, nw, d, index);
            }
              }
              m.RefinementBaseSig = RefinedSig;

              Contract.Assert(moduleUnderConstruction == m);  // this should be as it was set earlier in this method
        }
예제 #5
0
 /// <summary> Finds ILSpy's IModule based on ExprCS ModuleSignature. The IModule has access to the module contents, so it's much stronger than ModuleSignature. </summary>
 internal IModule GetModule(ModuleSignature module) =>
 moduleMap.TryGetValue(module, out var result) ? result :
 throw new ArgumentException($"Module {module} is not known.");