HarmonyOS鸿蒙Next中证书管理接口使用问题

HarmonyOS鸿蒙Next中证书管理接口使用问题 certificateManager.getPrivateCertificate 中包含证书的私钥吗?credentialData是什么格式的数据,能转换为X509Cert类型吗?这个数据怎么用于解密呢?

10 回复

尊敬的开发者,您好, 关于您反馈的问题:

1、不含私钥。私钥存在HUKS,只能 “引用” 不能导出。 2、credentialData为PEM格式的数据,可以转换为X509Cert类型。

3、getPrivateCertificate返回的credentialData不可用于证书数据解密。应当依托返回 keyUri,调用 certificateManager.init/finish接口,由HUKS内部私钥完成解密运算。

更多关于HarmonyOS鸿蒙Next中证书管理接口使用问题的实战系列教程也可以访问 https://www.itying.com/category-93-b0.html


开发者您好,针对您的问题:

1、不含私钥,getPrivateCertificate 的 credentialData 仅 X509 证书 DER 二进制,私钥存入 HUKS 安全域,凭据通过 keyUri 索引,无法导出明文私钥。

2、credentialData 为 DER 二进制 Uint8Array,用 cert.createX509Cert 传入 DER 编码结构体,可生成 X509Cert 实例,仅能提取公钥。

3、不可用证书数据解密,依托返回 keyUri,调用 certificateManager.init/finish 接口,由 HUKS 内部私钥完成解密运算。

参考文档:

https://device.harmonyos.com/cn/docs/apiref/harmonyos-guides/certmanager-private-credential-guidelines

https://device.harmonyos.com/cn/docs/apiref/harmonyos-guides/create-parse-verify-cert-object

背景知识:

  • getPrivateCertificate 返回的 credentialData 不含可直接导出的明文私钥;私钥存在 HUKS,只能 “引用” 不能导出。
  • credentialData 是 DER 编码的 X.509 证书二进制(Uint8Array),可以直接转成 X509Cert 对象
  • 解密不能拿 credentialData 自己解:要先用证书拿到公钥,私钥走 HUKS / CertManager 接口做解密

直接能转 X509Cert:

import { cert } from '@kit.DeviceCertificateKit';

// credentialData 即 getPrivateCertificate 拿到的 Uint8Array、
let x509Cert = await cert.createX509Cert(
    {
        data:Uint8Array
    },
    cert.EncodingFormat.FORMAT_DER // 注意是 DER
);

// 然后就能读公钥、有效期等
let pubKey = x509Cert.getPublicKey();

正确流程(RSA/SM2 解密):

  1. 拿到证书 & 公钥(你这边)
let res = await certificateManager.getPrivateCertificate(keyUri);
let certDer = res.credential.credentialData;
let x509Cert = await cert.createX509Cert(certDer, cert.EncodingFormat.FORMAT_DER);
let pubKey = x509Cert.getPublicKey(); // 给对方用来加密
  1. 对方用公钥加密(比如 RSA)
// 对方拿到你的 pubKey,加密
let cipherText = rsaEncrypt(plainText, pubKey);
  1. 你这边用私钥解密(必须用 CertManager/HUKS,不能自己拿私钥解
import { certificateManager } from '@ohos.security.certManager';

let decryptSpec: certificateManager.CMSignatureSpec = {
  purpose: certificateManager.CmKeyPurpose.CM_KEY_PURPOSE_DECRYPT,
  padding: certificateManager.CmKeyPadding.CM_PADDING_PKCS1,
  digest: certificateManager.CmKeyDigest.CM_DIGEST_SHA256
};

// 用 keyUri 引用 HUKS 里的私钥,系统替你解密
let handle = await certificateManager.init(keyUri, decryptSpec);
let result = await certificateManager.finishSession(handle, { inData: cipherText });
let plainText = new TextDecoder().decode(result.outData);

补充一个判断口径:getPrivateCertificate 不等于“把私钥取出来”。证书管理中安装的私有凭据由系统和密钥管理能力保护,应用侧拿到的是凭据标识、别名和证书数据,私钥明文不应该也不会导出。

因此可以分两条线处理:如果只是解析证书信息,把 credentialData 当作证书编码数据处理;如果要使用凭据里的私钥能力,应通过 keyUri 走 certificateManager.init/update/finish。需要注意,certManager 里的 CmKeyPurpose 目前是 SIGN/VERIFY,官方场景是签名、验签,不是把 credentialData 拿去做私钥解密。真正需要解密时,要改用支持 DECRYPT purpose 的 HUKS 密钥方案。

import { certificateManager, cert } from '@kit.DeviceCertificateKit';

const cmResult = await certificateManager.getPrivateCertificate(keyUri);
const credential = cmResult.credential;

// credentialData 如果是 DER 证书,可解析为 X509Cert。
const x509 = await cert.createX509Cert({
  data: credential.credentialData,
  encodingFormat: cert.EncodingFormat.FORMAT_DER
});

// 私钥能力通过 keyUri 使用,不导出私钥。
const spec: certificateManager.CMSignatureSpec = {
  purpose: certificateManager.CmKeyPurpose.CM_KEY_PURPOSE_SIGN,
  padding: certificateManager.CmKeyPadding.CM_PADDING_PSS,
  digest: certificateManager.CmKeyDigest.CM_DIGEST_SHA256
};
const handle = await certificateManager.init(keyUri, spec);
await certificateManager.update(handle.handle, data);
const signResult = await certificateManager.finish(handle.handle);

参考资料:应用证书凭据开发指导certManager APIcert.createX509Cert

接口详情如图所示 certificateManager.getPrivateCertificate 当获取私有凭据的详细信息成功时,err为null,data为CMResult对象中的credential属性;否则为错误对象。

cke_300.png

credentialData 的数据格式是 Uint8Array 也就是 是 Base64 编码的 PKCS#12(PFX)格式数据,或者说是经过封装的凭证信息。

能否转换为 X509Cert 类型?

直接转换: 不行。 credentialData 是 PFX 容器,不是纯 X.509 证书。

间接提取: 可以。 需要通过证书管理 API 提取 X.509 证书部分:

  • getPrivateCertificate 不含明文的私钥数据,但通过 keyUri 可安全使用私钥。
  • credentialData 是原始凭据(PKCS#12 等),可以提取证书并转为 X509Cert,但不能直接用于解密
  • 解密时必须使用 keyUri 获取 PrivateKey,配合 cryptoFramework.Cipher 完成。

certificateManager.getPrivateCertificate() 返回的是私有证书凭据(credential),并不是直接返回可导出的私钥。出于安全考虑,私钥通常由系统安全存储管理,应用无法直接获取私钥明文。

credentialData 一般是安装证书时导入的凭据数据(如 PKCS#12/PFX 等 keystore 二进制内容),不是 X509 证书本身,因此不能直接转换成 X509Cert

如果需要解析 X509 证书,需要先获取证书数据(DER/PEM),再通过 cert.createX509Cert() 创建 X509Cert 对象。

解密场景通常也不是取出私钥后自行解密,而是通过系统提供的密钥/证书相关接口,让系统使用证书关联的私钥完成签名或解密操作,私钥本身不会暴露给应用。

getPrivateCertificate 取到的是“应用证书凭据”的描述和证书链等信息,不建议把它理解成把私钥明文取出来给业务代码使用。私钥仍由证书/密钥管理能力保护,业务侧通常通过返回的 uri/authUri 调用 init/update/finish 完成签名或验签。

credentialData 更像凭据数据,不是直接拿来当 X509Cert 做解密的入口。如果你只是要解析公钥证书,可以看返回结构里是否有证书数据,再用证书解析接口处理;如果目的是“用私钥解密”,先确认该能力是否支持对应 purpose 和算法。证书管理文档里常见示例是安装私有凭据后做签名/验签,不是导出私钥后自行解密。

在 HarmonyOS NEXT 中,证书管理通过 @ohos.security.certificate 模块实现。核心接口包括 CertificateManagerX509Cert 等。使用前需在 module.json5 中声明 ohos.permission.ACCESS_CERT_MANAGER 权限。常见操作:调用 CertificateManager.importCert() 导入 PEM/DER 格式证书,通过 X509Cert.getIssuer() 等方法解析证书内容。注意接口返回 Promise 对象,需异步处理。API 版本要求 API 12+。

certificateManager.getPrivateCertificate 返回的 PrivateCertificate 对象同时包含证书(公钥)及其对应的私钥,因此可以直接用于需要私钥的场景。

credentialData 是证书的二进制编码数据,通常为 DER 格式(也可能为 PKCS#12 等其他封装)。该数据可以通过 new X509Cert(credentialData) 直接构造为 X509Cert 实例,前提是数据格式符合 X.509 证书规范。

解密操作需提取私钥:先通过 PrivateCertificate 获取私钥实例,再利用 CryptoFramework 创建非对称解密器(如 RSA/EC 解密),用该私钥对密文进行解密。credentialData 本身为证书公钥部分,不能直接用于解密,必须结合对应的私钥。

回到顶部