构建并校验证书链

从API版本26.0.0开始,证书链校验器提供证书链构建和校验能力,支持通过CertValidationParams参数配置构建和校验行为,包括信任锚设置、证书吊销检查、日期校验等。

开发步骤

  1. 导入@ohos.security.cert

    import { cert } from '@kit.DeviceCertificateKit';
    
  2. 基于已有的证书数据,创建待校验X509Cert证书对象。

  3. 调用cert.createCertChainValidator接口创建证书链校验器对象。

  4. 创建CertValidationParams校验参数对象。

  5. 调用validateCert(cert: X509Cert, params: CertValidationParams): Promise<CertValidationResult>接口构建并校验证书链,返回校验成功的证书链CertValidationResult

场景一:指定信任证书

当应用有自定义的信任锚证书时,可以通过trustedCerts参数指定信任的CA证书。


import { cert } from '@kit.DeviceCertificateKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { util } from '@kit.ArkTS';

// string转Uint8Array。
function stringToUint8Array(str: string): Uint8Array {
  const encoder = new util.TextEncoder();
  return encoder.encodeInto(str);
}

// ...

async function createX509Cert(certData: string): Promise<cert.X509Cert> {
  let encodingBlob: cert.EncodingBlob = {
    data: stringToUint8Array(certData),
    encodingFormat: cert.EncodingFormat.FORMAT_PEM
  };

  let x509Cert: cert.X509Cert = {} as cert.X509Cert;
  try {
    x509Cert = await cert.createX509Cert(encodingBlob);
  } catch (error) {
    let e: BusinessError = error as BusinessError;
    console.error(`createX509Cert failed: errCode: ${e.code}, message: ${e.message}`);
  }
  return x509Cert;
}

async function validateCertChainWithCustomTrustAnchor(): Promise<void> {
  try {
    // 创建证书对象
    let endEntityCert = await createX509Cert(endEntityCertData);
    let intermediateCaCert = await createX509Cert(intermediateCaCertData);
    let rootCaCert = await createX509Cert(rootCaCertData);

    // 构建校验参数
    let params: cert.X509CertValidatorParams = {
      // 不信任的中间证书,用于构建证书链
      untrustedCerts: [intermediateCaCert],
      // 信任锚证书,用于验证证书链
      trustedCerts: [rootCaCert],
      // 不信任系统预置CA证书
      trustSystemCa: false,
      date: '20260422121212Z'
    };
    // 创建证书链校验器实例
    let validator = cert.createCertChainValidator('PKIX');

    // 验证endEntityCert
    let result: cert.VerifyCertResult = await validator.validate(endEntityCert, params);
    console.info('validate success, certChain length: ' + result.certChain.length);
    for (let i = 0; i < result.certChain.length; i++) {
      let subject = result.certChain[i].getSubjectX500DistinguishedName().getName(cert.EncodingType.ENCODING_UTF8);
      console.info(`Cert ${i} subject: ${subject}`);
    }
  } catch (err) {
    // 校验失败
    let error = err as BusinessError;
    console.error('validate failed, errCode: ' + error.code + ', errMsg: ' + error.message);
  }
}

场景二:信任系统预置CA证书

当应用需要验证互联网公开证书(如HTTPS网站证书)时,可以使用系统预置的CA证书作为信任锚。通过设置trustSystemCatrue,校验器会使用系统预置CA证书库构建并验证证书链。


import { cert } from '@kit.DeviceCertificateKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { util } from '@kit.ArkTS';

// string转Uint8Array。
function stringToUint8Array(str: string): Uint8Array {
  const encoder = new util.TextEncoder();
  return encoder.encodeInto(str);
}

// ...

async function createX509Cert(certData: string): Promise<cert.X509Cert> {
  let encodingBlob: cert.EncodingBlob = {
    data: stringToUint8Array(certData),
    encodingFormat: cert.EncodingFormat.FORMAT_PEM
  };

  let x509Cert: cert.X509Cert = {} as cert.X509Cert;
  try {
    x509Cert = await cert.createX509Cert(encodingBlob);
  } catch (error) {
    let e: BusinessError = error as BusinessError;
    console.error(`createX509Cert failed: errCode: ${e.code}, message: ${e.message}`);
  }
  return x509Cert;
}

async function validateCertChainWithSystemCa(): Promise<void> {
  try {
    // 创建证书对象
    let endEntityCert = await createX509Cert(endEntityCertData);
    let intermediateCaCert = await createX509Cert(intermediateCaCertData);

    // 构建校验参数
    let params: cert.X509CertValidatorParams = {
      // 不信任的中间证书,用于构建证书链
      untrustedCerts: [intermediateCaCert],
      // 信任系统预置CA证书
      trustSystemCa: true,
      // 忽略证书过期或未生效
      ignoreErrs: [cert.CertResult.ERR_CERT_HAS_EXPIRED, cert.CertResult.ERR_CERT_NOT_YET_VALID],
    };

    // 创建证书链校验器实例
    let validator = cert.createCertChainValidator('PKIX');

    // 验证endEntityCert
    let result: cert.VerifyCertResult = await validator.validate(endEntityCert, params);
    console.info('validate success, certChain length: ' + result.certChain.length);
    for (let i = 0; i < result.certChain.length; i++) {
      let subject = result.certChain[i].getSubjectX500DistinguishedName().getName(cert.EncodingType.ENCODING_UTF8);
      console.info(`Cert ${i} subject: ${subject}`);
    }
  } catch (err) {
    let error = err as BusinessError;
    console.error('validate failed, errCode: ' + error.code + ', errMsg: ' + error.message);
  }
}

场景三:证书吊销校验(CRL)

可以通过crls参数指定CRL,用来检查证书是否被吊销。


import { cert } from '@kit.DeviceCertificateKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { util } from '@kit.ArkTS';

// string转Uint8Array。
function stringToUint8Array(str: string): Uint8Array {
  const encoder = new util.TextEncoder();
  return encoder.encodeInto(str);
}

// ...

async function createX509Cert(certData: string): Promise<cert.X509Cert> {
  let encodingBlob: cert.EncodingBlob = {
    data: stringToUint8Array(certData),
    encodingFormat: cert.EncodingFormat.FORMAT_PEM
  };

  let x509Cert: cert.X509Cert = {} as cert.X509Cert;
  try {
    x509Cert = await cert.createX509Cert(encodingBlob);
  } catch (error) {
    let e: BusinessError = error as BusinessError;
    console.error(`createX509Cert failed: errCode: ${e.code}, message: ${e.message}`);
  }
  return x509Cert;
}

async function createX509CRL(crlDataStr: string): Promise<cert.X509CRL> {
  let encodingBlob: cert.EncodingBlob = {
    data: stringToUint8Array(crlDataStr),
    encodingFormat: cert.EncodingFormat.FORMAT_PEM
  };

  let x509CRL: cert.X509CRL = {} as cert.X509CRL;
  try {
    x509CRL = await cert.createX509CRL(encodingBlob);
  } catch (error) {
    let e: BusinessError = error as BusinessError;
    console.error(`createX509CRL failed: errCode: ${e.code}, message: ${e.message}`);
  }
  return x509CRL;
}

async function validateCertChainWithCrl(): Promise<void> {
  try {
    // 创建证书对象
    let endEntityCert = await createX509Cert(endEntityCertData);
    let intermediateCaCert = await createX509Cert(intermediateCaCertData);
    let rootCaCert = await createX509Cert(rootCaCertData);

    // 创建CRL对象
    let crl = await createX509CRL(crlData);

    // 构建吊销校验参数
    let revokedParams: cert.X509CertRevokedParams = {
      // 启用CRL检查
      revocationFlags: [cert.CertRevocationFlag.CERT_REVOCATION_CRL_CHECK],
      // 提供CRL列表
      crls: [crl]
    };

    // 构建校验参数
    let params: cert.X509CertValidatorParams = {
      untrustedCerts: [intermediateCaCert],
      trustedCerts: [rootCaCert],
      trustSystemCa: false,
      // 不校验证书有效期(仅用于示例,实际场景建议开启)
      validateDate: false,
      // 设置吊销校验参数
      revokedParams: revokedParams,
    };

    // 创建证书链校验器实例
    let validator = cert.createCertChainValidator('PKIX');

    // 验证endEntityCert
    let result: cert.VerifyCertResult = await validator.validate(endEntityCert, params);
    console.info('validate success, certChain length: ' + result.certChain.length);
    for (let i = 0; i < result.certChain.length; i++) {
      let subject = result.certChain[i].getSubjectX500DistinguishedName().getName(cert.EncodingType.ENCODING_UTF8);
      console.info(`Cert ${i} subject: ${subject}`);
    }
  } catch (err) {
    let error = err as BusinessError;
    if (error.code === cert.CertResult.ERR_CERT_HAS_REVOKED) {
      console.error('certificate has been revoked');
    } else {
      console.error('validate failed, errCode: ' + error.code + ', errMsg: ' + error.message);
    }
  }
}

场景四:国密证书链校验

国密SM2证书链校验,通常需要设置userId参数。


import { cert } from '@kit.DeviceCertificateKit';
import { BusinessError } from '@kit.BasicServicesKit';
import { util } from '@kit.ArkTS';

function stringToUint8Array(str: string): Uint8Array {
  const encoder = new util.TextEncoder();
  return encoder.encodeInto(str);
}

// ...

async function createX509Cert(certData: string): Promise<cert.X509Cert> {
  let encodingBlob: cert.EncodingBlob = {
    data: stringToUint8Array(certData),
    encodingFormat: cert.EncodingFormat.FORMAT_PEM
  };

  let x509Cert: cert.X509Cert = {} as cert.X509Cert;
  try {
    x509Cert = await cert.createX509Cert(encodingBlob);
  } catch (error) {
    let e: BusinessError = error as BusinessError;
    console.error(`createX509Cert failed: errCode: ${e.code}, message: ${e.message}`);
  }
  return x509Cert;
}

async function validateSm2CertChain(): Promise<void> {
  try {
    let sm2EndEntityCert = await createX509Cert(sm2EndEntityCertData);
    let sm2IntermediateCaCert = await createX509Cert(sm2IntermediateCaCertData);
    let sm2RootCaCert = await createX509Cert(sm2RootCaCertData);

    let userId = new Uint8Array([
      0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
      0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38
    ]);

    let params: cert.X509CertValidatorParams = {
      // 不信任的中间证书,用于构建证书链
      untrustedCerts: [sm2IntermediateCaCert],
      // 信任锚证书,用于验证证书链
      trustedCerts: [sm2RootCaCert],
      // 不校验证书有效期(仅用于示例,实际场景建议开启)
      validateDate: false,
      // sm2验签使用的用户ID
      userId: userId
    };
    // 创建证书链校验器实例
    let validator = cert.createCertChainValidator('PKIX');

    // 验证sm2EndEntityCert证书
    let result: cert.VerifyCertResult = await validator.validate(sm2EndEntityCert, params);
    console.info('validate success, certChain length: ' + result.certChain.length);
    for (let i = 0; i < result.certChain.length; i++) {
      let subject = result.certChain[i].getSubjectX500DistinguishedName().getName(cert.EncodingType.ENCODING_UTF8);
      console.info(`Cert ${i} subject: ${subject}`);
      let alg = result.certChain[i].getSignatureAlgName()
      console.info(`Cert ${i} Signature Algorithm: ${alg}`);
    }
  } catch (err) {
    let error = err as BusinessError;
    console.error('validate failed, errCode: ' + error.code + ', errMsg: ' + error.message);
  }
}