Implementing Non-Anonymous Key Attestation with HarmonyOS Universal Keystore Kit
Prerequisites
Before using this functionality, you must request the ohos.permission.ATTEST_KEY permission. Developers should refer to the officail permission application procedures based on their application's APL level.
Linking Dynamic Libraries in CMake
target_link_libraries(your_target_name PUBLIC libhuks_ndk.z.so)
Implementation Process
- Define a Key Alias: Create a key alias string with a maximum length of 64 bytes.
- Initialize Parameter Sets: Use
OH_Huks_InitParamSet,OH_Huks_AddParams, andOH_Huks_BuildParamSetto construct parameter sets. These sets must includeOH_Huks_KeyAlg,OH_Huks_KeySize, andOH_Huks_KeyPurposeattributes. - Execute Key Attestation: Pass the key alias and parameter sets to the
OH_Huks_AttestKeyItemfunction to perform key attestation.
Code Example
#include "huks/native_huks_api.h"
#include "huks/native_huks_param.h"
#include <stdlib.h>
#include <string.h>
#define MAX_CERT_COUNT 4
#define CERT_BUFFER_SIZE 4096
#define CHALLENGE_STRING "attestation_challenge_data"
struct OH_Huks_Result createParamSet(struct OH_Huks_ParamSet **paramSetPtr,
const struct OH_Huks_Param *paramArray,
uint32_t paramArrayLength) {
struct OH_Huks_Result result = OH_Huks_InitParamSet(paramSetPtr);
if (result.errorCode != OH_HUKS_SUCCESS) {
return result;
}
result = OH_Huks_AddParams(*paramSetPtr, paramArray, paramArrayLength);
if (result.errorCode != OH_HUKS_SUCCESS) {
OH_Huks_FreeParamSet(paramSetPtr);
return result;
}
result = OH_Huks_BuildParamSet(paramSetPtr);
if (result.errorCode != OH_HUKS_SUCCESS) {
OH_Huks_FreeParamSet(paramSetPtr);
return result;
}
return result;
}
void releaseCertChain(struct OH_Huks_CertChain *chain, uint32_t releasedCerts) {
if (chain == NULL || chain->certificates == NULL) {
return;
}
for (uint32_t idx = 0; idx < releasedCerts; idx++) {
if (chain->certificates[idx].data != NULL) {
free(chain->certificates[idx].data);
chain->certificates[idx].data = NULL;
}
}
free(chain->certificates);
chain->certificates = NULL;
}
int32_t allocateCertChainMemory(struct OH_Huks_CertChain *chain) {
if (chain == NULL) {
return OH_HUKS_ERR_CODE_ILLEGAL_ARGUMENT;
}
chain->certCount = MAX_CERT_COUNT;
chain->certificates = (struct OH_Huks_Blob *)malloc(sizeof(struct OH_Huks_Blob) * chain->certCount);
if (chain->certificates == NULL) {
return OH_HUKS_ERR_CODE_INTERNAL_ERROR;
}
for (uint32_t i = 0; i < chain->certCount; i++) {
chain->certificates[i].size = CERT_BUFFER_SIZE;
chain->certificates[i].data = (uint8_t *)malloc(chain->certificates[i].size);
if (chain->certificates[i].data == NULL) {
releaseCertChain(chain, i);
return OH_HUKS_ERR_CODE_ILLEGAL_ARGUMENT;
}
}
return 0;
}
static struct OH_Huks_Param keyGenerationParams[] = {
{ .tag = OH_HUKS_TAG_ALGORITHM, .uint32Param = OH_HUKS_ALG_RSA },
{ .tag = OH_HUKS_TAG_KEY_SIZE, .uint32Param = OH_HUKS_RSA_KEY_SIZE_2048 },
{ .tag = OH_HUKS_TAG_PURPOSE, .uint32Param = OH_HUKS_KEY_PURPOSE_VERIFY },
{ .tag = OH_HUKS_TAG_DIGEST, .uint32Param = OH_HUKS_DIGEST_SHA256 },
{ .tag = OH_HUKS_TAG_PADDING, .uint32Param = OH_HUKS_PADDING_PSS },
{ .tag = OH_HUKS_TAG_BLOCK_MODE, .uint32Param = OH_HUKS_MODE_ECB },
};
static struct OH_Huks_Blob attestChallenge = { sizeof(CHALLENGE_STRING), (uint8_t *)CHALLENGE_STRING };
static napi_value performKeyAttestation(napi_env env, napi_callback_info info) {
struct OH_Huks_Blob keyAlias = {
(uint32_t)strlen("sample_key_alias"),
(uint8_t *)"sample_key_alias"
};
static struct OH_Huks_Param attestationParams[] = {
{ .tag = OH_HUKS_TAG_ATTESTATION_CHALLENGE, .blob = attestChallenge },
{ .tag = OH_HUKS_TAG_ATTESTATION_ID_ALIAS, .blob = keyAlias },
};
struct OH_Huks_ParamSet *genParamSet = NULL;
struct OH_Huks_ParamSet *attestParamSet = NULL;
struct OH_Huks_Result operationResult;
struct OH_Huks_Blob certData = { 0 };
struct OH_Huks_CertChain certChain = { &certData, 0 };
do {
operationResult = createParamSet(&genParamSet, keyGenerationParams, sizeof(keyGenerationParams) / sizeof(struct OH_Huks_Param));
if (operationResult.errorCode != OH_HUKS_SUCCESS) {
break;
}
operationResult = createParamSet(&attestParamSet, attestationParams, sizeof(attestationParams) / sizeof(struct OH_Huks_Param));
if (operationResult.errorCode != OH_HUKS_SUCCESS) {
break;
}
operationResult = OH_Huks_GenerateKeyItem(&keyAlias, genParamSet, NULL);
if (operationResult.errorCode != OH_HUKS_SUCCESS) {
break;
}
(void)allocateCertChainMemory(&certChain);
operationResult = OH_Huks_AttestKeyItem(&keyAlias, attestParamSet, &certChain);
} while (0);
releaseCertChain(&certChain, MAX_CERT_COUNT);
OH_Huks_FreeParamSet(&genParamSet);
OH_Huks_FreeParamSet(&attestParamSet);
(void)OH_Huks_DeleteKeyItem(&keyAlias, NULL);
napi_value returnValue;
napi_create_int32(env, operationResult.errorCode, &returnValue);
return returnValue;
}