diff options
| author | bruvzg <7645683+bruvzg@users.noreply.github.com> | 2019-10-04 18:01:13 +0300 | 
|---|---|---|
| committer | bruvzg <7645683+bruvzg@users.noreply.github.com> | 2019-10-04 22:33:03 +0300 | 
| commit | 1c592e5f1f500c45b5ac3b0bf80a9040310a3a55 (patch) | |
| tree | be00c4f45a5ae5b209b0b9200704d9949b131125 /platform/windows/export/export.cpp | |
| parent | d86c9ef2e691ced51175136b42a9cce2a8c54227 (diff) | |
Add code signing support for Windows exports (using "signtool" on Windows and "osslsigncode" on the other platforms)
Diffstat (limited to 'platform/windows/export/export.cpp')
| -rw-r--r-- | platform/windows/export/export.cpp | 185 | 
1 files changed, 183 insertions, 2 deletions
diff --git a/platform/windows/export/export.cpp b/platform/windows/export/export.cpp index 827daa2d58..3abb05b494 100644 --- a/platform/windows/export/export.cpp +++ b/platform/windows/export/export.cpp @@ -31,6 +31,7 @@  #include "core/os/file_access.h"  #include "core/os/os.h"  #include "editor/editor_export.h" +#include "editor/editor_node.h"  #include "editor/editor_settings.h"  #include "platform/windows/logo.gen.h" @@ -38,11 +39,22 @@ static Error fixup_embedded_pck(const String &p_path, int64_t p_embedded_start,  class EditorExportPlatformWindows : public EditorExportPlatformPC { +	Error _code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path); +  public:  	virtual Error export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags = 0); +	virtual Error sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path);  	virtual void get_export_options(List<ExportOption> *r_options);  }; +Error EditorExportPlatformWindows::sign_shared_object(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path) { +	if (p_preset->get("codesign/enable")) { +		return _code_sign(p_preset, p_path); +	} else { +		return OK; +	} +} +  Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {  	Error err = EditorExportPlatformPC::export_project(p_preset, p_debug, p_path, p_flags); @@ -133,12 +145,28 @@ Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset>  	OS::get_singleton()->execute(wine_path, args, true);  #endif -	return OK; +	if (p_preset->get("codesign/enable") && err == OK) { +		err = _code_sign(p_preset, p_path); +	} + +	return err;  }  void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_options) {  	EditorExportPlatformPC::get_export_options(r_options); +	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/enable"), false)); +#ifdef WINDOWS_ENABLED +	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/identity_type", PROPERTY_HINT_ENUM, "Select automatically,Use PKCS12 file (specify *.PFX/*.P12 file),Use certificate store (specify SHA1 hash)"), 0)); +#endif +	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/identity", PROPERTY_HINT_GLOBAL_FILE, "*.pfx,*.p12"), "")); +	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/password"), "")); +	r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "codesign/timestamp"), true)); +	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/timestamp_server_url"), "")); +	r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "codesign/digest_algorithm", PROPERTY_HINT_ENUM, "SHA1,SHA256"), 1)); +	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "codesign/description"), "")); +	r_options->push_back(ExportOption(PropertyInfo(Variant::POOL_STRING_ARRAY, "codesign/custom_options"), PoolStringArray())); +  	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/icon", PROPERTY_HINT_FILE, "*.ico"), ""));  	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), ""));  	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/product_version", PROPERTY_HINT_PLACEHOLDER_TEXT, "1.0.0"), "")); @@ -149,11 +177,164 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio  	r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));  } +Error EditorExportPlatformWindows::_code_sign(const Ref<EditorExportPreset> &p_preset, const String &p_path) { +	List<String> args; + +#ifdef WINDOWS_ENABLED +	String signtool_path = EditorSettings::get_singleton()->get("export/windows/signtool"); +	if (signtool_path != String() && !FileAccess::exists(signtool_path)) { +		ERR_PRINTS("Could not find signtool executable at " + signtool_path + ", aborting."); +		return ERR_FILE_NOT_FOUND; +	} +	if (signtool_path == String()) { +		signtool_path = "signtool"; // try to run signtool from PATH +	} +#else +	String signtool_path = EditorSettings::get_singleton()->get("export/windows/osslsigncode"); +	if (signtool_path != String() && !FileAccess::exists(signtool_path)) { +		ERR_PRINTS("Could not find osslsigncode executable at " + signtool_path + ", aborting."); +		return ERR_FILE_NOT_FOUND; +	} +	if (signtool_path == String()) { +		signtool_path = "osslsigncode"; // try to run signtool from PATH +	} +#endif + +	args.push_back("sign"); + +	//identity +#ifdef WINDOWS_ENABLED +	int id_type = p_preset->get("codesign/identity_type"); +	if (id_type == 0) { //auto select +		args.push_back("/a"); +	} else if (id_type == 1) { //pkcs12 +		if (p_preset->get("codesign/identity") != "") { +			args.push_back("/f"); +			args.push_back(p_preset->get("codesign/identity")); +		} else { +			EditorNode::add_io_error("codesign: no identity found"); +			return FAILED; +		} +	} else if (id_type == 2) { //Windows certificate store +		if (p_preset->get("codesign/identity") != "") { +			args.push_back("/sha1"); +			args.push_back(p_preset->get("codesign/identity")); +		} else { +			EditorNode::add_io_error("codesign: no identity found"); +			return FAILED; +		} +	} else { +		EditorNode::add_io_error("codesign: invalid identity type"); +		return FAILED; +	} +#else +	if (p_preset->get("codesign/identity") != "") { +		args.push_back("-pkcs12"); +		args.push_back(p_preset->get("codesign/identity")); +	} else { +		EditorNode::add_io_error("codesign: no identity found"); +		return FAILED; +	} +#endif + +	//password +	if (p_preset->get("codesign/password") != "") { +#ifdef WINDOWS_ENABLED +		args.push_back("/p"); +#else +		args.push_back("-pass"); +#endif +		args.push_back(p_preset->get("codesign/password")); +	} + +	//timestamp +	if (p_preset->get("codesign/timestamp")) { +		if (p_preset->get("codesign/timestamp_server") != "") { +#ifdef WINDOWS_ENABLED +			args.push_back("/tr"); +			args.push_back(p_preset->get("codesign/timestamp_server_url")); +			args.push_back("/td"); +			if ((int)p_preset->get("codesign/digest_algorithm") == 0) { +				args.push_back("sha1"); +			} else { +				args.push_back("sha256"); +			} +#else +			args.push_back("-ts"); +			args.push_back(p_preset->get("codesign/timestamp_server_url")); +#endif +		} else { +			EditorNode::add_io_error("codesign: invalid timestamp server"); +			return FAILED; +		} +	} + +	//digest +#ifdef WINDOWS_ENABLED +	args.push_back("/fd"); +#else +	args.push_back("-h"); +#endif +	if ((int)p_preset->get("codesign/digest_algorithm") == 0) { +		args.push_back("sha1"); +	} else { +		args.push_back("sha256"); +	} + +	//description +	if (p_preset->get("codesign/description") != "") { +#ifdef WINDOWS_ENABLED +		args.push_back("/d"); +#else +		args.push_back("-n"); +#endif +		args.push_back(p_preset->get("codesign/description")); +	} + +	//user options +	PoolStringArray user_args = p_preset->get("codesign/custom_options"); +	for (int i = 0; i < user_args.size(); i++) { +		String user_arg = user_args[i].strip_edges(); +		if (!user_arg.empty()) { +			args.push_back(user_arg); +		} +	} + +#ifndef WINDOWS_ENABLED +	args.push_back("-in"); +#endif +	args.push_back(p_path); +#ifndef WINDOWS_ENABLED +	args.push_back("-out"); +	args.push_back(p_path); +#endif + +	String str; +	Error err = OS::get_singleton()->execute(signtool_path, args, true, NULL, &str, NULL, true); +	ERR_FAIL_COND_V(err != OK, err); + +	print_line("codesign (" + p_path + "): " + str); +#ifndef WINDOWS_ENABLED +	if (str.find("SignTool Error") != -1) { +#else +	if (str.find("Failed") != -1) { +#endif +		return FAILED; +	} + +	return OK; +} +  void register_windows_exporter() {  	EDITOR_DEF("export/windows/rcedit", "");  	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/rcedit", PROPERTY_HINT_GLOBAL_FILE, "*.exe")); -#ifndef WINDOWS_ENABLED +#ifdef WINDOWS_ENABLED +	EDITOR_DEF("export/windows/signtool", ""); +	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/signtool", PROPERTY_HINT_GLOBAL_FILE, "*.exe")); +#else +	EDITOR_DEF("export/windows/osslsigncode", ""); +	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/osslsigncode", PROPERTY_HINT_GLOBAL_FILE));  	// On non-Windows we need WINE to run rcedit  	EDITOR_DEF("export/windows/wine", "");  	EditorSettings::get_singleton()->add_property_hint(PropertyInfo(Variant::STRING, "export/windows/wine", PROPERTY_HINT_GLOBAL_FILE));  |