Local Code Sign Service — AI Knowledge Base
Basic Information
| Attribute | Value |
|---|---|
| Module Name | local_code_sign |
| Subsystem | base/security |
| Parent Guide | AGENTS.md |
| Primary Language | C++ |
| SystemAbility | SA ID: 3507 |
| Last Updated | 2026-07-10 |
Before Editing
Before making changes, write a 3-line declaration referencing both this guide and the parent guide:
- Task category: Change SA implementation / Change IPC stub / Change HUKS integration / Change permission check / Change build / Change test / Change documentation.
- Documents read: Sections from this guide + parent AGENTS.md relevant sections +
errcode.h+ header paths of files being changed. - Constraints identified: Which items from the "Do Not / Ask Before / Module Invariants" sections below are triggered.
Where to Look
| Task type | Read these first |
|---|---|
| Modify SA 3507 IPC interface (stub) | src/local_code_sign_stub.cpp + include/local_code_sign_stub.h + this guide's "IPC Pattern" section + parent AGENTS.md's "Do Not — SA 3507 IPC" |
| Modify signing logic or HUKS integration | src/local_sign_key.cpp + include/local_sign_key.h + this guide's "HUKS Integration" section |
| Modify permission verification | src/permission_utils.cpp + include/permission_utils.h + this guide's "Permission Verification" section |
| Modify service lifecycle | src/local_code_sign_service.cpp + include/local_code_sign_service.h + sa_profile/3507.json |
| Modify build configuration | BUILD.gn (module-local) + code_signature.gni (parent) |
| Add new IPC method | This guide's "IPC Pattern" + errcode.h for new error codes + parent AGENTS.md's "Ask Before — public API" |
Routing by Vocabulary
| Term / Abbreviation | Meaning / Location | Knowledge to load |
|---|---|---|
LocalCodeSignStub / IPC code / MessageParcel |
IPC stub implementation | local_code_sign_stub.cpp + this guide's "IPC Pattern" |
LocalSignKey / HUKS / ECDSA256 |
HUKS key management and signing | local_sign_key.cpp + this guide's "HUKS Integration" |
SA 3507 / LocalCodeSignService |
SystemAbility registration and lifecycle | local_code_sign_service.cpp + sa_profile/3507.json + parent AGENTS.md's "Ask Before — SA 3507" |
IsValidCallerOf* / SELinux / AccessToken |
Permission verification | permission_utils.cpp + this guide's "Permission Verification" |
DECLARE_DELAYED_SINGLETON / SystemAbility::MakeAndRegisterAbility |
Service registration pattern | This guide's "SystemAbility Lifecycle" and "Singleton Pattern" |
Module Structure
local_code_sign/
├── src/
│ ├── local_code_sign_service.cpp # Main service implementation
│ ├── local_code_sign_stub.cpp # IPC request handling
│ ├── local_sign_key.cpp # HUKS key management & signing
│ └── permission_utils.cpp # SELinux/AccessToken verification
├── include/
│ ├── local_code_sign_service.h # Service header
│ ├── local_code_sign_stub.h # IPC stub header
│ ├── local_sign_key.h # Key management header
│ └── permission_utils.h # Permission utilities
├── BUILD.gn # Build configuration
├── local_code_sign.cfg # Init service config
├── sa_profile/3507.json # SystemAbility profile
└── config/ # Certificate configs
Key Dependencies
- HUKS: Certificate storage and signing
- SAMGR: SystemAbility management
- OpenSSL: PKCS7 signature generation
- AccessToken: Permission verification
- HiSysEvent: Security event logging
- HiTrace: Performance tracing
Build and Test
Build Commands
# Build only local_code_sign service
./build.sh --product-name rk3568 --build-target base/security/code_signature/services/local_code_sign:liblocal_code_sign
# Using hb (independent compilation)
cd services/local_code_sign && hb build . -i
# Build all code_signature tests
./build.sh --product-name rk3568 --build-target base/security/code_signature/test:testgroup --no-indep
Test Commands
# Build specific local_code_sign unit test
./build.sh --product-name rk3568 --build-target base/security/code_signature/test/unittest:local_code_sign_unittest
# Run test on device (after pushing)
hdc file send out/rk3568/tests/unittest/code_signature/code_signature/local_code_sign_unittest /data/test/
hdc shell /data/test/local_code_sign_unittest
# Run specific test case
hdc shell "/data/test/local_code_sign_unittest --gtest_filter=LocalCodeSignTest.LocalCodeSignTest_0001"
Lint
# Format C++ source files according to the project's code style
If the formatter is not available, note "lint skipped" in the Final Response.
Verification Loop
Done Definition
A task is considered complete only when all of the following are satisfied:
Final Response
When reporting back, the response must include:
- Changed file list + diff summary per file.
- Constraint check conclusion: Which "Do Not / Ask Before / Module Invariants" items were hit and the outcome.
- Validation commands run and their results.
- Impact scope: SA ID 3507, IPC methods, permission model, HUKS operations affected.
- Risk points and items not run with explicit reasons.
When Validation Cannot Run
- On-device tests unreachable: At minimum run local build + lint, note "device test not run".
- Only docs / build config changed: "No code changes, unit tests not required", but still run one build to confirm no breakage.
Constraints and Boundaries
Do Not
The following must not be changed without escalation to the module owner.
- SA 3507 IPC interface: Do not modify
LocalCodeSignStubIPC fields, SA ID, or IPC codes. These are cross-process contracts — changes break all callers (see parent AGENTS.mdDo Not — SA 3507 IPCfor rationale). - HUKS certificate lifecycle: Do not bypass HUKS for certificate operations. Key generation, initialization, and signing must follow the three-stage flow (
HksInit→HksUpdate→HksFinish). - Permission check bypass: Do not remove or bypass the SELinux / AccessToken check (
PermissionUtils::IsValidCallerOfXXX()) in any IPC method. This is a mandatory security control. - SELinux check ordering: Do not move the permission check to after data reading — it must be the first operation in every IPC
Inner()method. - Error code meanings: Do not invent new error codes outside
errcode.h. Return only codes defined ininterfaces/inner_api/common/include/errcode.h. - Local certificate generation: If HUKS certificate retrieval fails, do not generate or substitute a local certificate.
Ask Before
The following require human confirmation before changes.
- Adding a new IPC method to
LocalCodeSignStub— requires SA ID 3507 contract review and coordination with all IPC callers. - Changing the signature or semantics of existing IPC methods — requires cross-team coordination (installer, compiler service, etc.).
- Changing the key algorithm from ECDSA256 or modifying the three-stage HUKS flow — requires security review.
- Adding new permission roles or modifying
IsValidCallerOf*logic — requires security review. - Modifying
sa_profile/3507.json— this file may be generated by the packaging system; confirm the source of truth first.
Module Invariants
- Every IPC
Inner()method must: check permission first, read input, call service implementation, write output/reply. - Every signing operation must use a valid HUKS key handle. Do not fall back to software signing.
- Owner ID validation must enforce
MAX_OWNER_ID_LEN(32 bytes). Empty owner ID is valid but producesCS_ERR_NO_OWNER_ID. - Error logging must use
LOG_ERRORbefore returning, with%{public}specifier for security (never log raw certificate data).
Known Pitfalls
- IPC ordering: The permission check is the first line of every
Inner()method. Inserting code before it can create security bypasses. - HUKS three-stage flow:
HksInit()→HksUpdate()→HksFinish()must be completed in order. Skipping stages or reordering causes signing failures. - Challenge-response:
SetChallenge()must be called beforeInitLocalCertificate(). Forgetting this breaks the handshake protocol. - fs-verity integration: Use
FsverityUtilsHelper::GetInstance().GenerateFormattedDigest()for file digests. The default hash algorithm is SHA256.
Coding Patterns
Naming
- Classes:
PascalCase(LocalCodeSignService,LocalSignKey) - Methods:
PascalCasefor public,camelCasefor private - Constants:
kPascalCaseorUPPER_CASE(LOCAL_SIGN_KEY_ALIAS,MAX_OWNER_ID_LEN) - File names:
snake_case.cpp(local_code_sign_service.cpp) - Headers:
snake_case.hwith#ifndef OHOS_SNAKE_CASE_Hguards
Imports Order
- Project headers with paths:
#include "local_code_sign_service.h" - System headers:
#include <cstdint>,#include <mutex>
Formatting (OpenHarmony C++ Style)
- Use
std::lock_guard<std::mutex>for mutex locking - Use
constexprfor compile-time constants - Use
std::make_uniqueinstead ofnewfor single ownership - Use
deleteand set tonullptrfor cleanup - Use
memcpy_sinstead ofmemcpyfor secure copying
Error Handling
// Return error codes from errcode.h (defined in interfaces/inner_api/common/include/errcode.h)
// All error codes are negative integers (CS_SUCCESS = 0)
// Common patterns:
if (!condition) {
LOG_ERROR("Description with details: %{public}d", value);
return CS_ERR_CODE;
}
// Always log errors before returning
// Use %{public} specifier in LOG_* macros for security (avoids leaking sensitive data)
IPC Pattern (LocalCodeSignStub)
// Each IPC method has an Inner() function that handles MessageParcel
int32_t LocalCodeSignStub::MethodNameInner(MessageParcel &data, MessageParcel &reply) {
// 1. Permission check (always first)
if (!PermissionUtils::IsValidCallerOfXXX()) {
reply.WriteInt32(CS_ERR_NO_PERMISSION);
return CS_ERR_NO_PERMISSION;
}
// 2. Read input from data parcel
Type param;
if (!data.ReadType(param)) {
LOG_ERROR("Read failed.");
return CS_ERR_IPC_READ_DATA;
}
// 3. Call service implementation
Type output;
int32_t result = MethodName(param, output);
// 4. Write result and output to reply
if (!reply.WriteInt32(result) || !reply.WriteType(output)) {
return CS_ERR_IPC_WRITE_DATA;
}
return CS_SUCCESS;
}
SystemAbility Lifecycle
// Service registration (in .cpp)
const bool REGISTER_RESULT = SystemAbility::MakeAndRegisterAbility(
DelayedSingleton<LocalCodeSignService>::GetInstance().get());
// OnStart: Initialize, Publish, set state, schedule unload task
// OnStop: Clear state, remove tasks, set state to NOT_START
Singleton Pattern
// Use DECLARE_DELAYED_SINGLETON(Class) in class declaration
// Use DelayedSingleton<Class>::GetInstance() to access
class LocalCodeSignService {
DECLARE_DELAYED_SINGLETON(LocalCodeSignService);
DECLARE_SYSTEM_ABILITY(LocalCodeSignService);
};
HUKS Integration (LocalSignKey)
// Key lifecycle: GenerateKey() → InitKey() → Sign()
// Use ECC 256-bit keys for signing (ECDSA256)
// Challenge-Response: SetChallenge() before InitLocalCertificate()
// Three-stage signing: HksInit() → HksUpdate() → HksFinish()
Permission Verification
// Valid callers defined in permission_utils.cpp:
// - InitLocalCertificate: "key_enable"
// - SignLocalCode: "compiler_service"
// Check via PermissionUtils::IsValidCallerOfXXX()
Owner ID Constraints
- Maximum length: 32 bytes (
MAX_OWNER_ID_LEN) - Must be validated before signing:
if (ownerID.length() > MAX_OWNER_ID_LEN) - Empty owner ID is valid (results in
CS_ERR_NO_OWNER_IDwhen parsing)
fs-verity Integration
- Use
FsverityUtilsHelper::GetInstance().GenerateFormattedDigest()to get file digest - Default hash algorithm: SHA256