VMOS Cloud API
  • 简体中文
  • English
  • 简体中文
  • English
  • 产品介绍
  • 产品类型
  • 产品计费
  • OpenAPI
    • 接口文档
    • 错误码
    • 实例属性列表
    • 安卓改机属性列表
  • Android端 SDK
    • 示例搭建
    • 接口说明
    • 回调函数
    • 错误码
    • 更新日志
  • Web H5端 SDK
    • 示例搭建
    • 接口说明
    • 回调函数
    • 错误码
    • 更新日志
  • Windows PC端 SDK
    • 示例搭建
    • 接口说明
    • 回调函数
    • 更新日志
  • 端侧与云机通信开发
    • AIDL接入方式
    • 系统服务API(aidl)
  • 类XP、LSP Hook框架
  • 相关协议

手机根证书格式说明

证书格式概述

手机根证书采用JSON格式存储,包含ECC和RSA两种加密算法的证书链。每个证书链包含根证书、中间证书和叶子证书,以及对应的私钥。所有证书和密钥均采用DER格式,并以Base64编码存储。证书链最多支持两个中间证书,按照顺序命名为intermediate0和intermediate1。

JSON结构

{
    "ecc_key": "xxxx",                    // ECC私钥,DER格式,Base64编码
    "ecc_cert_leaf": "xxxx",             // ECC叶子证书,DER格式,Base64编码
    "ecc_cert_intermediate0": "xxxx",    // ECC第一个中间证书,DER格式,Base64编码
    "ecc_cert_intermediate1": "xxxx",    // ECC第二个中间证书(可选),DER格式,Base64编码
    "ecc_cert_root": "xxxx",             // ECC根证书,DER格式,Base64编码
    "rsa_key": "xxxx",                   // RSA私钥,DER格式,Base64编码
    "rsa_cert_leaf": "xxxx",             // RSA叶子证书,DER格式,Base64编码
    "rsa_cert_intermediate0": "xxxx",    // RSA第一个中间证书,DER格式,Base64编码
    "rsa_cert_intermediate1": "xxxx",    // RSA第二个中间证书(可选),DER格式,Base64编码
    "rsa_cert_root": "xxxx"              // RSA根证书,DER格式,Base64编码
}

字段说明

ECC证书链

  • ecc_key: ECC私钥,DER格式,Base64编码
  • ecc_cert_leaf: ECC叶子证书,DER格式,Base64编码
  • ecc_cert_intermediate0: ECC第一个中间证书,DER格式,Base64编码
  • ecc_cert_intermediate1: ECC第二个中间证书(可选),DER格式,Base64编码
  • ecc_cert_root: ECC根证书,DER格式,Base64编码

RSA证书链

  • rsa_key: RSA私钥,DER格式,Base64编码
  • rsa_cert_leaf: RSA叶子证书,DER格式,Base64编码
  • rsa_cert_intermediate0: RSA第一个中间证书,DER格式,Base64编码
  • rsa_cert_intermediate1: RSA第二个中间证书(可选),DER格式,Base64编码
  • rsa_cert_root: RSA根证书,DER格式,Base64编码

注意事项

  • 所有证书和密钥均采用DER格式,并以Base64编码存储
  • 证书链必须完整,包含根证书、中间证书和叶子证书
  • 私钥必须与对应的证书匹配
  • 中间证书最多支持两个,按照顺序命名为intermediate0和intermediate1

转换工具

可以使用Python脚本将keybox.xml格式转换为上述JSON格式。转换脚本会:

  1. 解析keybox.xml文件中的PEM格式证书和密钥
  2. 将PEM格式转换为DER格式
  3. 对DER格式数据进行Base64编码
  4. 生成最终的JSON格式输出

转换脚本需要以下Python库:

# coding=utf-8
import sys

import json
import hashlib
from cryptography.hazmat.backends import default_backend
from cryptography.x509 import load_pem_x509_certificate
from cryptography.hazmat.primitives import serialization
import base64
import xml.etree.ElementTree as ET

def pem_cert_to_der_cert_base64(pem_cert):
    try:
        # Try to load as a certificate first
        pub_key = load_pem_x509_certificate(pem_cert.encode(), default_backend())
        der_certificate = pub_key.public_bytes(
            encoding=serialization.Encoding.DER
        )
    except ValueError:
        # If not a certificate, try to load as a private key
        priv_key = serialization.load_pem_private_key(pem_cert.encode(), password=None, backend=default_backend())
        der_certificate = priv_key.private_bytes(
            encoding=serialization.Encoding.DER,
            format=serialization.PrivateFormat.TraditionalOpenSSL,
            encryption_algorithm=serialization.NoEncryption()
        )
    return base64.b64encode(der_certificate).decode('utf-8')

def generate_new_der_attest_key(root_pem_attest_key):
    root_attest_key = root_pem_attest_key
    new_attest_key = {}
    ecc_key = root_attest_key["ecc_key"]
    ecc_cert_leaf = root_attest_key["ecc_cert_leaf"]
    new_attest_key["ecc_key"] = pem_cert_to_der_cert_base64(ecc_key)
    new_attest_key["ecc_cert_leaf"] = pem_cert_to_der_cert_base64(ecc_cert_leaf)
    new_attest_key["ecc_cert_root"] = pem_cert_to_der_cert_base64(root_attest_key["ecc_cert_root"])

    rsa_key = root_attest_key["rsa_key"]
    rsa_cert_leaf = root_attest_key["rsa_cert_leaf"]
    new_attest_key["rsa_key"] = pem_cert_to_der_cert_base64(rsa_key)
    new_attest_key["rsa_cert_leaf"] = pem_cert_to_der_cert_base64(rsa_cert_leaf)
    new_attest_key["rsa_cert_root"] = pem_cert_to_der_cert_base64(root_attest_key["rsa_cert_root"])

    atkeys = root_attest_key.keys()
    for atkey in atkeys:
        if atkey.startswith("ecc_cert_intermediate") or atkey.startswith("rsa_cert_intermediate"):
            new_attest_key[atkey] =  pem_cert_to_der_cert_base64(root_attest_key[atkey])

    return new_attest_key

def generate_key_batch(root_pem_attest_key, root_attest_key_md5, batch_size):
    batch_keys = []
    for _ in range(batch_size):
        new_der_attest_key = generate_new_der_attest_key(root_pem_attest_key)
        der_attest_key_str = json.dumps(new_der_attest_key)
        key_md5 = hashlib.md5(der_attest_key_str.encode('utf-8')).hexdigest()
        batch_keys.append((root_attest_key_md5, key_md5, der_attest_key_str))
    return batch_keys


def parse_xml_keybox(file_path):
    tree = ET.parse(file_path)

    attest_keys = {}

    for keybox in tree.getroot().findall("Keybox"):
        attest_key = {}
        _DeviceID = keybox.get("DeviceID")
        keys = keybox.findall("Key")
        if len(keys) != 2:
            print(f"wrong key {_DeviceID}")
            continue
        for _key in keys:
            _key_algorithm = _key.get("algorithm")
            _key_type = "ecc"
            if _key_algorithm == "ecdsa":
                _key_type = "ecc"
            elif _key_algorithm == "rsa":
                _key_type = "rsa"
            else:
                print(f"wrong key algorithm{_key_algorithm} for {_DeviceID}")

            _pem_privkey = _key.find("PrivateKey").text
            _num_certs = int(_key.find("CertificateChain").find("NumberOfCertificates").text)
            if _num_certs < 2:
                print(f"wrong cert {_DeviceID}")
                break
            _certs = _key.find("CertificateChain").findall("Certificate")
            _leaf_pem_cert = _certs[0].text
            _root_pem_cert = _certs[-1].text
            attest_key[_key_type + "_key"] = _pem_privkey
            attest_key[_key_type + "_cert_leaf"] = _leaf_pem_cert
            attest_key[_key_type + "_cert_root"] = _root_pem_cert

            intermediate_idx = 0
            for intermediate_cert in _certs[1:-1]:
                # print(intermediate_cert.text)
                attest_key[_key_type + "_cert_intermediate" + str(intermediate_idx)] = intermediate_cert.text
                intermediate_idx += 1
        attest_keys[hashlib.md5(json.dumps(attest_key).encode('utf-8')).hexdigest()] = attest_key
    return attest_keys

if __name__ == '__main__':
    root_attest_keys = parse_xml_keybox("keybox.xml")

    for root_pem_attest_key in root_attest_keys.values():
        new_der_attest_key = generate_new_der_attest_key(root_pem_attest_key)
        print(json.dumps(new_der_attest_key, indent=4))

        break