Android VB

以A/B system为例:

VB1.0

edk2/abl/QcomModulePkg/Library/avb/VerifiedBoot.c

STATIC EFI_STATUS LoadImageAndAuthVB1 (BootInfo *Info)
{
  ......
	  Status = Info->VbIntf->VBDeviceInit (Info->VbIntf,
	                                       (device_info_vb_t *)&DevInfo_vb);
	  if (Status != EFI_SUCCESS) {
	    DEBUG ((EFI_D_ERROR, "Error during VBDeviceInit: %r\n", Status));
	    return Status;
	  }
	
	  AsciiStrnCpyS (StrPnameAscii, ARRAY_SIZE (StrPnameAscii), "/",
	                 AsciiStrLen ("/"));
	  UnicodeStrToAsciiStr (Info->Pname, PnameAscii);
	  if (Info->MultiSlotBoot) {
	    AsciiStrnCatS (StrPnameAscii, ARRAY_SIZE (StrPnameAscii), PnameAscii,
	                   AsciiStrLen (PnameAscii) - (MAX_SLOT_SUFFIX_SZ - 1));
	  } else {
	    AsciiStrnCatS (StrPnameAscii, ARRAY_SIZE (StrPnameAscii), PnameAscii,
	                   AsciiStrLen (PnameAscii));
	  }
	
	  Status =
	      Info->VbIntf->VBVerifyImage (Info->VbIntf, (UINT8 *)StrPnameAscii,
	                                   (UINT8 *)Info->Images[0].ImageBuffer,
	                                   Info->Images[0].ImageSize, &Info->BootState);
	  if (Status != EFI_SUCCESS || Info->BootState == BOOT_STATE_MAX) {                                                                                                                     
	    DEBUG ((EFI_D_ERROR, "VBVerifyImage failed with: %r\n", Status));
	    return Status;
	  }
  .......
  }

VB1在normal boot时bootloader会去验证boot.img,验证pass加载启动,看下高通的实现:

boot_images/QcomPkg/Drivers/VerifiedBootDxe/VerifiedBootDxe.c

EFI_STATUS
QCOM_VB_VerifyImage(IN QCOM_VERIFIEDBOOT_PROTOCOL *This,
                    IN UINT8 pname[MAX_PNAME_LENGTH], IN UINT8 *img,
                    IN UINT32 img_len, OUT boot_state_t *bootstate)
{
  EFI_STATUS status = EFI_FAILURE;
  struct boot_img_hdr *img_hdr = NULL;
  VB_HASH hash_algorithm = VB_SHA256;
  UINTN hash_size = VB_SHA256_SIZE;
  UINT8 img_hash[hash_size];
  UINT32 startTime = 0;
  UINT32 endTime = 0;

  startTime = GetTimerCountms();
  if (!is_device_init_called) {

    dev_boot_state = BOOT_STATE_MAX;
    goto exit;
  }
  if (!pname || !img || !bootstate || img_len == 0 || img_len > MAX_UINT64 - (UINT64)img) {

    dev_boot_state = BOOT_STATE_MAX;
    status = EFI_INVALID_PARAMETER;
    goto exit;
  }

  /* Skip verification in case the dev_boot_state (initialized by
 * QCOM_VB_DeviceInit API) is Orange */
  if (dev_boot_state == ORANGE) {
    status = EFI_SUCCESS;
    goto exit;
  }
  /* Read Android Verified Boot Signature from the image */
  if (vb_read_embedded_vb_signature(pEfiQcomASN1X509Protocol, img, img_len, &embedded_vb_signature) != EFI_SUCCESS) {
    dev_boot_state = RED;
    status = EFI_SUCCESS;
    goto exit;
  }
  /* Read OEM certificate from the embedded header file */
  if (vb_read_oem_certificate(pEfiQcomASN1X509Protocol, &oem_certificate) != EFI_SUCCESS) {
    dev_boot_state = RED;
    status = EFI_SUCCESS;
    goto exit;
  }
  /* Calculate the hash of image */
  if (vb_get_image_hash(pEfiQcomASN1X509Protocol, pname, img, img_len, &embedded_vb_signature, img_hash,
                        hash_size, hash_algorithm) != EFI_SUCCESS) {
    dev_boot_state = RED;
    status = EFI_SUCCESS;
    goto exit;
  }
  /* Verify the hash of image with OEM key */
  if (vb_verify_hash_oem_certificate(pEfiQcomASN1X509Protocol, img_hash, hash_algorithm, &oem_certificate,
                                     &embedded_vb_signature) != EFI_SUCCESS) {
    dev_boot_state = YELLOW;
    /* Verify the hash of image with embedded key */
    if (vb_verify_hash_embedded_key(pEfiQcomASN1X509Protocol, img_hash, hash_algorithm,
                                    &embedded_vb_signature) != EFI_SUCCESS) {
      dev_boot_state = RED;
      status = EFI_SUCCESS;
      goto exit;
    }
    cert_verification_passed = TRUE;
  } else {

    dev_boot_state = GREEN;
  }
  status = EFI_SUCCESS;
/*Struct def for boot image header*/
typedef struct boot_img_hdr
{
  CHAR8 magic[8];
  UINT32 kernel_size;  /* size in bytes */
  UINT32 kernel_addr;  /* physical load addr */
  UINT32 ramdisk_size; /* size in bytes */
  UINT32 ramdisk_addr; /* physical load addr */
  UINT32 second_size;  /* size in bytes */
  UINT32 second_addr;  /* physical load addr */
  UINT32 tags_addr;    /* physical addr for kernel tags */
  UINT32 page_size;    /* flash page size we assume */
  UINT32 dt_size;      /* device_tree in bytes */
  UINT32 os_version;   /* version << 11 | patch_level */
  UINT8 name[16]; /* ascii product name */
  UINT8 cmdline[512];
  UINT32 id[8]; /* timestamp / checksum / sha1 / etc */
}boot_img_hdr;

可以清楚的看到,整个过程是这样的,
1、从img(boot)获取vb的Signature
2、读取OEM的certificate,各家不同
3、计算img(boot)的hash,当然根据不同的hash_algorithm
4、然后使用OEM certificate验证hash是否匹配
如果大家对4中如何验证hash好奇的话,可以参考:

EFI_STATUS VerifySignature(
    CONST UINT8 *signature_ptr,
    UINT32 signature_len,
    UINT8 *hash,
    VB_HASH hash_algorithm,
    CONST UINT8 *modulus,
    UINT32 modulus_len,
    CONST UINT8 *public_exp,
    UINT32 public_exp_len)
{

  EFI_STATUS status = EFI_FAILURE;
  CE_RSA_KEY key;
  BigInt modulus_bi;
  BigInt public_exp_bi;
  INT32 hashidx;
  INT32 hash_len;
  UINT32 padding_type;
  VOID *padding_info = NULL;
  QCOM_SECRSA_PROTOCOL *pEfiQcomSecRSAProtocol = NULL;
  SetMem(&key, sizeof(CE_RSA_KEY), 0);

  switch (hash_algorithm) {
  case VB_SHA256:
    hashidx = CE_HASH_IDX_SHA256;
    hash_len = VB_SHA256_SIZE;
    break;
  default:
    DEBUG((EFI_D_ERROR, "VB: VerifySignature: Hash algorithm not supported\n"));
    status = EFI_UNSUPPORTED;
    goto exit;
  }
  key.N = AllocatePool(sizeof(S_BIGINT));
  if (key.N == NULL) {
    DEBUG((EFI_D_ERROR, "VB: VerifySignature: mem allocation err for key.N\n"));
    goto exit;
  }
  key.e = AllocatePool(sizeof(S_BIGINT));
  if (key.e == NULL) {
    DEBUG((EFI_D_ERROR, "VB: VerifySignature: mem allocation err for key.e\n"));
    goto exit;
  }
  status = gBS->LocateProtocol(&gEfiQcomSecRSAProtocolGuid, NULL, (VOID **) &pEfiQcomSecRSAProtocol);
  if ( status != EFI_SUCCESS)
  {
     DEBUG((EFI_D_ERROR, "VB: VerifySignature: LocateProtocol failed, status = %x\n", status));
    goto exit;
  }
  status = pEfiQcomSecRSAProtocol->SecRSABigIntReadBin(pEfiQcomSecRSAProtocol, modulus, modulus_len, &modulus_bi);
  if ( status != EFI_SUCCESS)
  {
    DEBUG((EFI_D_ERROR, "VB: VerifySignature: SecRSABigIntReadBin for modulus failed!, ret = %x\n", status));
    goto exit;
  }
  status = pEfiQcomSecRSAProtocol->SecRSABigIntReadBin(pEfiQcomSecRSAProtocol, public_exp, public_exp_len,  &public_exp_bi);
  if ( status != EFI_SUCCESS)
  {
	DEBUG((EFI_D_ERROR, "VB: VerifySignature: SecRSABigIntReadBin for modulus failed!, ret = %x\n", status));
	goto exit;
  }

  key.N->bi = modulus_bi;
  key.e->bi = public_exp_bi;
  key.e->sign = S_BIGINT_POS;
  key.type = CE_RSA_KEY_PUBLIC;
  padding_type = CE_RSA_PAD_PKCS1_V1_5_SIG;

  status = pEfiQcomSecRSAProtocol->SecRSAVerifySig(pEfiQcomSecRSAProtocol, &key, padding_type, padding_info, hashidx,hash, hash_len, (UINT8*)signature_ptr, signature_len);
  if (status != EFI_SUCCESS) {
    goto exit;
  }
  status = EFI_SUCCESS;

简单来说就是RSA公钥验签名,参考:RSA - 原理、特点(加解密及签名验签)及公钥和私钥的生成
关于kernel如何通过cmdline传来的verity key验证system分区,参考:system分区签名校验方法
简化如下,system.img细分system data / verity-metadata.img / verity.img,
分别数据内容是 system data / (dm-verity table) + (signature) / hash tree。
hash tree是将system data以4k大小划分,使用sha256生成的一颗描述system data的树;
dm-verity table是调用build_verity_metadata.py生成描述改hashtree的metadata,如果verity key
验证system signature pass,kernel会使用这个dm-verity table通过dm-verity驱动创建dm-verity块设备;
signature就是使用非对称加密算法生成对dm-verity table的数字签名;
具体的path可以参考:
system/extras/verity
system/core/fs_mgr

VB2.0

vb1.0使用OEM key验证boot分区,使用verity key验证system/vendor分区,但vb2.0使用OEM key验证vbmeta.img,并使用其中包含的public key验证其他分区(system/vendor/boot等)。Android O以后boot分区只放了kernel,bootloader需要用公钥校验vbmeta的签名,以及boot签名和system签名,签名验证通过之后才允许下一步booting,校验签名完成之后,会启动kernel,并把system分区中的rootfs相关的dm-verity数据通过cmdline的形式传递给kernel,kernel启动会挂载rootfs(注意rootfs中包含了system,两者为同一个分区),所以可以认为system的挂载是在kernel中完成的,并且使用dm-verity模式进行的挂载。

edk2/abl/QcomModulePkg/Library/avb/libavb/avb_vbmeta_image.h

 * The vbmeta image consists of three blocks:
 *
 *  +-----------------------------------------+
 *  | Header data - fixed size                |                                                                                                                                         
 *  +-----------------------------------------+
 *  | Authentication data - variable size     |
 *  +-----------------------------------------+
 *  | Auxiliary data - variable size          |
 *  +-----------------------------------------+
 *
 * The "Header data" block is described by this struct and is always
 * |AVB_VBMETA_IMAGE_HEADER_SIZE| bytes long.
 *
 * The "Authentication data" block is |authentication_data_block_size|
 * bytes long and contains the hash and signature used to authenticate
 * the vbmeta image. The type of the hash and signature is defined by
 * the |algorithm_type| field.
 *
 * The "Auxiliary data" is |auxiliary_data_block_size| bytes long and
 * contains the auxiliary data including the public key used to make
 * the signature and descriptors.
 * 
 typedef struct AvbVBMetaImageHeader {
  /*   0: Four bytes equal to "AVB0" (AVB_MAGIC). */
  uint8_t magic[AVB_MAGIC_LEN];

  /*   4: The major version of libavb required for this header. */
  uint32_t required_libavb_version_major;
  /*   8: The minor version of libavb required for this header. */
  uint32_t required_libavb_version_minor;

  /*  12: The size of the signature block. */
  uint64_t authentication_data_block_size;
  /*  20: The size of the auxiliary data block. */
  uint64_t auxiliary_data_block_size;

  /*  28: The verification algorithm used, see |AvbAlgorithmType| enum. */
  uint32_t algorithm_type;

  /*  32: Offset into the "Authentication data" block of hash data. */
  uint64_t hash_offset;
  /*  40: Length of the hash data. */
  uint64_t hash_size;

  /*  48: Offset into the "Authentication data" block of signature data. */
  uint64_t signature_offset;
  /*  56: Length of the signature data. */
  uint64_t signature_size;

  /*  64: Offset into the "Auxiliary data" block of public key data. */
  uint64_t public_key_offset;
  /*  72: Length of the public key data. */
  uint64_t public_key_size;

  /*  80: Offset into the "Auxiliary data" block of public key metadata. */
  uint64_t public_key_metadata_offset;
  /*  88: Length of the public key metadata. Must be set to zero if there
   *  is no public key metadata.
   */
  uint64_t public_key_metadata_size;

  /*  96: Offset into the "Auxiliary data" block of descriptor data. */
  uint64_t descriptors_offset;
  /* 104: Length of descriptor data. */
  uint64_t descriptors_size;

  /* 112: The rollback index which can be used to prevent rollback to
   *  older versions.
   */
  uint64_t rollback_index;

  /* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be
   * set to zero if the vbmeta image is not a top-level image.
   */
  uint32_t flags;

  /* 124: Reserved to ensure |release_string| start on a 16-byte
   * boundary. Must be set to zeroes.
   */
  uint8_t reserved0[4];

  /* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or
   * "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL
   * terminated. Applications must not make assumptions about how this
   * string is formatted.
   */
  uint8_t release_string[AVB_RELEASE_STRING_SIZE];

  /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE
   * bytes. This must be set to zeroes.
   */
  uint8_t reserved[80];
} AVB_ATTR_PACKED AvbVBMetaImageHeader;

从上面可以得到header的大小为256byte,当然如果用avbtool也可以得到vbmeta的信息:

Minimum libavb version:   1.0
Header Block:             256 bytes
Authentication Block:     XXX bytes
Auxiliary Block:          XXX bytes
Algorithm:                SHA256_RSA2048
Rollback Index:           0
Flags:                    0
Release String:           'avbtool 1.X.X'
Descriptors:
    Hash descriptor:
      Image Size:            
      Hash Algorithm:        
      Partition Name:      
      Salt:                  
      Digest:                
      Flags:                 
    Hashtree descriptor:
      Version of dm-verity:  
      Image Size:            
      Tree Offset:           
      Tree Size:             
      Data Block Size:       
      Hash Block Size:       
      FEC num roots:         
      FEC offset:            
      FEC size:              
      Hash Algorithm:        

Android O 引入了 dtbo 和 vendor.img。这些 image 挨个校验可以说费时费力,而 AVB 2.0 的做法事实上十分简单,引入一个新的分区:vbmeta.img(verified boot metadata),然后把所有需要校验的内容在编译时就计算好打包到这个分区,那么启动过程中 BootLoader 只需要校验 vbmeta.img,就能确认 vbmeta 内的数据是否可信。再用 vbmeta 中的数据去比对 bootimg,dtbo,system,img,vendor.img 即可

Authentication data block 包含两部分内容:Hash data 和 signature data,

def verify_vbmeta_signature(vbmeta_header, vbmeta_blob):
  """Checks that the signature in a vbmeta blob was made by
     the embedded public key.

  Arguments:
    vbmeta_header: A AvbVBMetaHeader.
    vbmeta_blob: The whole vbmeta blob, including the header.

  Returns:
    True if the signature is valid and corresponds to the embedded
    public key. Also returns True if the vbmeta blob is not signed.
  """
  (_, alg) = lookup_algorithm_by_type(vbmeta_header.algorithm_type)
  if alg.hash_name == '':
    return True
  header_blob = vbmeta_blob[0:256]
  auth_offset = 256
  aux_offset = auth_offset + vbmeta_header.authentication_data_block_size
  aux_size = vbmeta_header.auxiliary_data_block_size
  aux_blob = vbmeta_blob[aux_offset:aux_offset + aux_size]
  pubkey_offset = aux_offset + vbmeta_header.public_key_offset
  pubkey_size = vbmeta_header.public_key_size
  pubkey_blob = vbmeta_blob[pubkey_offset:pubkey_offset + pubkey_size]

  digest_offset = auth_offset + vbmeta_header.hash_offset
  digest_size = vbmeta_header.hash_size
  digest_blob = vbmeta_blob[digest_offset:digest_offset + digest_size]

  sig_offset = auth_offset + vbmeta_header.signature_offset
  sig_size = vbmeta_header.signature_size
  sig_blob = vbmeta_blob[sig_offset:sig_offset + sig_size]

  # Now that we've got the stored digest, public key, and signature
  # all we need to do is to verify. This is the exactly the same
  # steps as performed in the avb_vbmeta_image_verify() function in
  # libavb/avb_vbmeta_image.c.

  ha = hashlib.new(alg.hash_name)
  ha.update(header_blob)
  ha.update(aux_blob)

Auxiliary data block包含两部分内容:AvbDescriptor 和 RSA public key,对应上面的vbmeta可以清晰的看出
它其中所包含的信息。

typedef struct AvbDescriptor {
  uint64_t tag;
  uint64_t num_bytes_following;
} AVB_ATTR_PACKED AvbDescriptor;

typedef enum {
  AVB_DESCRIPTOR_TAG_PROPERTY,
  AVB_DESCRIPTOR_TAG_HASHTREE,
  AVB_DESCRIPTOR_TAG_HASH,
  AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE,
  AVB_DESCRIPTOR_TAG_CHAIN_PARTITION,
} AvbDescriptorTag;

typedef struct AvbHashDescriptor {
  AvbDescriptor parent_descriptor;
  uint64_t image_size;
  uint8_t hash_algorithm[32];
  uint32_t partition_name_len;
  uint32_t salt_len;
  uint32_t digest_len;
  uint8_t reserved[64];
} AVB_ATTR_PACKED AvbHashDescriptor;

参考:
Android verified boot 2.0 vbmeta 数据结构解析
Android P中的AVB校验

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值