From a0db10a86af9e296512193ce98fb54b22e18aef8 Mon Sep 17 00:00:00 2001 From: zfeixiang Date: Mon, 30 Jun 2025 16:08:34 +0800 Subject: [PATCH 1/3] sign plugin id Signed-off-by: zfeixiang --- .../codesigning/exception/CodeSignErrMsg.java | 33 +++++++ .../sign/BcSignedDataGenerator.java | 16 ++++ .../codesigning/sign/CodeSigning.java | 16 +++- .../codesigning/utils/HapUtils.java | 95 ++++++++++++++++++- 4 files changed, 157 insertions(+), 3 deletions(-) diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/exception/CodeSignErrMsg.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/exception/CodeSignErrMsg.java index aa1ac5aa..efa4df0f 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/exception/CodeSignErrMsg.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/exception/CodeSignErrMsg.java @@ -99,6 +99,17 @@ public class CodeSignErrMsg { .addSolution("Add 'bundle-info' to the profile file") .build(); + /** + * PROFILE_PLUGIN_ID_NOT_EXISTED_ERROR + */ + public static final ErrorMsg PROFILE_PLUGIN_ID_NOT_EXISTED_ERROR = ErrorMsg.getCodeSignErrBuilder() + .addTypeCode("12") + .addErrCode("001") + .addDescription("Profile Content Error") + .addCause("'pluginDistributionIDs' not found in profile file") + .addSolution("Add 'pluginDistributionIDs' to the profile file") + .build(); + /** * PROFILE_APPID_VALUE_TYPE_ERROR */ @@ -110,6 +121,17 @@ public class CodeSignErrMsg { .addSolution("Value type of app-identifier should be string") .build(); + /** + * PROFILE_PLUGIN_ID_VALUE_TYPE_ERROR + */ + public static final ErrorMsg PROFILE_PLUGIN_ID_VALUE_TYPE_ERROR = ErrorMsg.getCodeSignErrBuilder() + .addTypeCode("12") + .addErrCode("001") + .addDescription("Profile Content Error") + .addCause("Value type of pluginDistributionIDs is not string") + .addSolution("Value type of pluginDistributionIDs should be string") + .build(); + /** * PROFILE_APPID_VALUE_LENGTH_ERROR */ @@ -121,6 +143,17 @@ public class CodeSignErrMsg { .addSolution("Modify to a valid app-identifier in profile file") .build(); + /** + * PROFILE_PLUGIN_ID_VALUE_LENGTH_ERROR + */ + public static final ErrorMsg PROFILE_PLUGIN_ID_VALUE_LENGTH_ERROR = ErrorMsg.getCodeSignErrBuilder() + .addTypeCode("12") + .addErrCode("001") + .addDescription("Profile Content Error") + .addCause("Value length of pluginDistributionIDs is invalid") + .addSolution("Modify to a valid pluginDistributionIDs in profile file") + .build(); + /** * PROFILE_JSON_PARSE_ERROR */ diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/BcSignedDataGenerator.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/BcSignedDataGenerator.java index 9dcc9770..1f78029e 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/BcSignedDataGenerator.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/BcSignedDataGenerator.java @@ -74,6 +74,11 @@ public class BcSignedDataGenerator implements SignedDataGenerator { */ public static final String SIGNER_OID = "1.3.6.1.4.1.2011.2.376.1.4.1"; + /** + * PLUGIN ID of the signer identity + */ + public static final String SIGNER_PLUGIN_ID = "1.3.6.1.4.1.2011.2.376.1.4.2"; + private static final LogUtils LOGGER = new LogUtils(BcSignedDataGenerator.class); private static final SignatureAlgorithmIdentifierFinder SIGN_ALG_ID_FINDER @@ -84,10 +89,16 @@ public class BcSignedDataGenerator implements SignedDataGenerator { private String ownerID; + private String pluginId; + public void setOwnerID(String ownerID) { this.ownerID = ownerID; } + public void setPluginId(String pluginId) { + this.pluginId = pluginId; + } + @Override public byte[] generateSignedData(byte[] content, SignerConfig signConfig) throws CodeSignException { if (content == null) { @@ -197,6 +208,11 @@ public class BcSignedDataGenerator implements SignedDataGenerator { new DERSet(new DERUTF8String(ownerID))); table.add(ownerIDAttr); } + if (pluginId != null) { + Attribute pluginIDAttr = new Attribute(new ASN1ObjectIdentifier(SIGNER_PLUGIN_ID), + new DERSet(new DERUTF8String(pluginId))); + table.add(pluginIDAttr); + } return new DERSet(table); } diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/CodeSigning.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/CodeSigning.java index 1e1bf4a1..bc3e1f54 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/CodeSigning.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/CodeSigning.java @@ -80,6 +80,11 @@ public class CodeSigning { */ public static final String HAP_SIGNATURE_ENTRY_NAME = "Hap"; + /** + * bundle type of plugin + */ + public static final String BUNDLE_TYPE_PLUGIN = "appPlugin"; + private static final LogUtils LOGGER = new LogUtils(CodeSigning.class); private final SignerConfig signConfig; @@ -88,6 +93,8 @@ public class CodeSigning { private PageInfoExtension pageInfoExtension; + private String pluginId; + /** * provide code sign functions to sign a hap * @@ -182,8 +189,11 @@ public class CodeSigning { FsVerityInfoSegment fsVerityInfoSegment = new FsVerityInfoSegment(FsVerityDescriptor.VERSION, FsVerityGenerator.getFsVerityHashAlgorithm(), FsVerityGenerator.getLog2BlockSize()); this.codeSignBlock.setFsVerityInfoSegment(fsVerityInfoSegment); - - LOGGER.debug("Sign hap."); + String moduleContent = HapUtils.getModuleContent(input); + String bundleType = HapUtils.getAppPluginFromJson(moduleContent); + if (BUNDLE_TYPE_PLUGIN.equals(bundleType)) { + pluginId = HapUtils.parsePluginId(profileContent); + } String ownerID = HapUtils.getAppIdentifier(profileContent); try (FileInputStream inputStream = new FileInputStream(input)) { Pair hapSignInfoAndMerkleTreeBytesPair = signFile(inputStream, dataSize, true, @@ -486,11 +496,13 @@ public class CodeSigning { } BcSignedDataGenerator bcSignedDataGenerator = new BcSignedDataGenerator(); bcSignedDataGenerator.setOwnerID(ownerID); + bcSignedDataGenerator.setPluginId(pluginId); return bcSignedDataGenerator.generateSignedData(signedData, copiedConfig); } else { copiedConfig = signConfig.copy(); BcSignedDataGenerator bcSignedDataGenerator = new BcSignedDataGenerator(); bcSignedDataGenerator.setOwnerID(ownerID); + bcSignedDataGenerator.setPluginId(pluginId); return bcSignedDataGenerator.generateSignedData(signedData, copiedConfig); } } diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java index f3053573..dfd695e6 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java @@ -28,7 +28,10 @@ import com.ohos.hapsigntool.entity.Pair; import com.ohos.hapsigntool.error.ProfileException; import com.ohos.hapsigntool.utils.LogUtils; +import java.io.BufferedReader; +import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; @@ -194,7 +197,7 @@ public class HapUtils { public static Map getHnpsFromJson(JarFile inputJar) throws IOException, ProfileException { // get module.json Map hnpNameMap = new HashMap<>(); - JarEntry moduleEntry = inputJar.getJarEntry("module.json"); + JarEntry moduleEntry = inputJar.getJarEntry(HAP_STAGE_MODULE_JSON_FILE); if (moduleEntry == null) { return hnpNameMap; } @@ -226,4 +229,94 @@ public class HapUtils { return hnpNameMap; } + /** + * parse app-id and profileType from profile + * + * @param profileContent the content of profile + * @return Pair value of app-id and profileType + * @throws ProfileException profile is invalid + */ + public static String parsePluginId(String profileContent) throws ProfileException { + String pluginID = null; + String pluginIDKey = "pluginDistributionIDs"; + String capabilitiesKey = "app-services-capabilities"; + String permissionKey = "ohos.permission.kernel.SUPPORT_PLUGIN"; + try { + JsonElement parser = JsonParser.parseString(profileContent); + if (parser == null || parser.isJsonNull()) { + throw new ProfileException(CodeSignErrMsg.PROFILE_JSON_PARSE_ERROR.toString()); + } + JsonObject profileJson = parser.getAsJsonObject(); + JsonObject capabilitiesObject = profileJson.getAsJsonObject(capabilitiesKey); + if (capabilitiesObject == null || !capabilitiesObject.isJsonObject() || !capabilitiesObject.has( + permissionKey)) { + throw new ProfileException(CodeSignErrMsg.PROFILE_PLUGIN_ID_NOT_EXISTED_ERROR.toString()); + } + JsonObject permissionObject = capabilitiesObject.getAsJsonObject(permissionKey); + if (permissionObject == null || !permissionObject.isJsonObject() || !permissionObject.has(pluginIDKey)) { + throw new ProfileException(CodeSignErrMsg.PROFILE_PLUGIN_ID_NOT_EXISTED_ERROR.toString()); + } + JsonElement permissionElement = permissionObject.get(pluginIDKey); + if (permissionElement == null || !permissionElement.getAsJsonPrimitive().isString()) { + throw new ProfileException(CodeSignErrMsg.PROFILE_PLUGIN_ID_VALUE_TYPE_ERROR.toString()); + } + pluginID = permissionElement.getAsString(); + } catch (JsonSyntaxException | UnsupportedOperationException e) { + throw new ProfileException(CodeSignErrMsg.PROFILE_JSON_PARSE_ERROR.toString(), e); + } + if (pluginID == null || pluginID.isEmpty()) { + throw new ProfileException(CodeSignErrMsg.PROFILE_PLUGIN_ID_VALUE_LENGTH_ERROR.toString()); + } + return pluginID; + } + + /** + * get map of hnp name and type from module.json + * + * @param moduleContent module Content + * @return packageName-type map + * @throws ProfileException profile is invalid + */ + public static String getAppPluginFromJson(String moduleContent) throws ProfileException { + String bundleType = ""; + if (moduleContent == null || moduleContent.isEmpty()) { + return bundleType; + } + try { + JsonElement jsonElement = JsonParser.parseString(moduleContent); + if (jsonElement == null || jsonElement.isJsonNull()) { + throw new ProfileException(CodeSignErrMsg.MODULE_JSON_PARSE_ERROR.toString()); + } + JsonObject jsonObject = jsonElement.getAsJsonObject(); + JsonObject moduleObject = jsonObject.getAsJsonObject("app"); + + JsonPrimitive type = moduleObject.getAsJsonPrimitive("bundleType"); + if (type != null && !type.getAsString().isEmpty()) { + bundleType = type.getAsString(); + } + } catch (JsonSyntaxException | UnsupportedOperationException e) { + throw new ProfileException(CodeSignErrMsg.MODULE_JSON_PARSE_ERROR.toString(), e); + } + return bundleType; + } + + public static String getModuleContent(File input) throws IOException { + try (JarFile inputJar = new JarFile(input, false)) { + JarEntry moduleEntry = inputJar.getJarEntry(HAP_STAGE_MODULE_JSON_FILE); + if (moduleEntry == null) { + return null; + } + try (InputStream inputStream = inputJar.getInputStream(moduleEntry); + BufferedReader reader = new BufferedReader( + new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { + StringBuilder sb = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + sb.append(line); + } + return sb.toString(); + } + } + } + } -- Gitee From 58a939c59f10678005ef4be1912c9fde9cd9b713 Mon Sep 17 00:00:00 2001 From: zfeixiang Date: Thu, 3 Jul 2025 15:42:59 +0800 Subject: [PATCH 2/3] sign plugin id Signed-off-by: zfeixiang --- .../codesigning/sign/CodeSigning.java | 2 +- .../hapsigntool/codesigning/utils/HapUtils.java | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/CodeSigning.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/CodeSigning.java index bc3e1f54..c7a512b3 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/CodeSigning.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/sign/CodeSigning.java @@ -190,7 +190,7 @@ public class CodeSigning { FsVerityGenerator.getFsVerityHashAlgorithm(), FsVerityGenerator.getLog2BlockSize()); this.codeSignBlock.setFsVerityInfoSegment(fsVerityInfoSegment); String moduleContent = HapUtils.getModuleContent(input); - String bundleType = HapUtils.getAppPluginFromJson(moduleContent); + String bundleType = HapUtils.getBundleTypeFromJson(moduleContent); if (BUNDLE_TYPE_PLUGIN.equals(bundleType)) { pluginId = HapUtils.parsePluginId(profileContent); } diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java index dfd695e6..cf252676 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java @@ -230,10 +230,10 @@ public class HapUtils { } /** - * parse app-id and profileType from profile + * parse pluginDistributionIDs from profile * * @param profileContent the content of profile - * @return Pair value of app-id and profileType + * @return value of pluginDistributionIDs * @throws ProfileException profile is invalid */ public static String parsePluginId(String profileContent) throws ProfileException { @@ -271,13 +271,13 @@ public class HapUtils { } /** - * get map of hnp name and type from module.json + * get bundle type from module.json * * @param moduleContent module Content - * @return packageName-type map + * @return bundle type value * @throws ProfileException profile is invalid */ - public static String getAppPluginFromJson(String moduleContent) throws ProfileException { + public static String getBundleTypeFromJson(String moduleContent) throws ProfileException { String bundleType = ""; if (moduleContent == null || moduleContent.isEmpty()) { return bundleType; @@ -300,6 +300,12 @@ public class HapUtils { return bundleType; } + /** + * get module.json content from input file + * @param input file + * @return module.json content + * @throws IOException when IO error occurred + */ public static String getModuleContent(File input) throws IOException { try (JarFile inputJar = new JarFile(input, false)) { JarEntry moduleEntry = inputJar.getJarEntry(HAP_STAGE_MODULE_JSON_FILE); -- Gitee From bfd77f60dfe82c6a8ba782fa088fe631d9698000 Mon Sep 17 00:00:00 2001 From: zfeixiang Date: Thu, 3 Jul 2025 22:32:02 +0800 Subject: [PATCH 3/3] sign plugin id Signed-off-by: zfeixiang --- .../com/ohos/hapsigntool/codesigning/utils/HapUtils.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java index cf252676..691d102b 100644 --- a/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java +++ b/hapsigntool/hap_sign_tool_lib/src/main/java/com/ohos/hapsigntool/codesigning/utils/HapUtils.java @@ -288,9 +288,11 @@ public class HapUtils { throw new ProfileException(CodeSignErrMsg.MODULE_JSON_PARSE_ERROR.toString()); } JsonObject jsonObject = jsonElement.getAsJsonObject(); - JsonObject moduleObject = jsonObject.getAsJsonObject("app"); - - JsonPrimitive type = moduleObject.getAsJsonPrimitive("bundleType"); + JsonObject appObject = jsonObject.getAsJsonObject("app"); + if (appObject == null || !appObject.isJsonObject() || !appObject.has("bundleType")) { + return bundleType; + } + JsonPrimitive type = appObject.getAsJsonPrimitive("bundleType"); if (type != null && !type.getAsString().isEmpty()) { bundleType = type.getAsString(); } -- Gitee