(root)/
util-linux-2.39/
libblkid/
src/
superblocks/
bitlocker.c
       1  /*
       2   * Copyright (C) 2018 Karel Zak <kzak@redhat.com>
       3   *
       4   * This file may be redistributed under the terms of the
       5   * GNU Lesser General Public License.
       6   */
       7  #include <stdio.h>
       8  #include <stdlib.h>
       9  #include <unistd.h>
      10  #include <string.h>
      11  #include <errno.h>
      12  #include <ctype.h>
      13  #include <stdint.h>
      14  
      15  #include "superblocks.h"
      16  
      17  #define BDE_HDR_SIZE	512
      18  #define BDE_HDR_OFFSET	0
      19  
      20  struct bde_header_win7 {
      21  /*   0 */ unsigned char	boot_entry_point[3];
      22  /*   3 */ unsigned char	fs_signature[8];
      23  /*  11 */ unsigned char	__dummy1[67 - 11];
      24  /*  67 */ uint32_t      volume_serial;		/* NTFS uses 64bit serial number */
      25  /*  71 */ unsigned char volume_label[11];	/* "NO NAME\x20\x20\x20\x20" only */
      26  /*  82 */ unsigned char __dummy2[160 - 82];
      27  /* 160 */ unsigned char guid[16];		/* BitLocker specific GUID */
      28  /* 176 */ uint64_t      fve_metadata_offset;
      29  } __attribute__((packed));
      30  
      31  
      32  struct bde_header_togo {
      33  /*   0 */ unsigned char	boot_entry_point[3];
      34  /*   3 */ unsigned char	fs_signature[8];
      35  /*  11 */ unsigned char	__dummy[424 - 11];
      36  /* 424 */ unsigned char guid[16];
      37  /* 440 */ uint64_t      fve_metadata_offset;
      38  } __attribute__((packed));
      39  
      40  
      41  struct bde_fve_metadata {
      42  /*   0 */ unsigned char  signature[8];
      43  /*   8 */ uint16_t       size;
      44  /*  10 */ uint16_t       version;
      45  };
      46  
      47  enum {
      48  	BDE_VERSION_VISTA = 0,
      49  	BDE_VERSION_WIN7,
      50  	BDE_VERSION_TOGO
      51  };
      52  
      53  #define BDE_MAGIC_VISTA		"\xeb\x52\x90-FVE-FS-"
      54  #define BDE_MAGIC_WIN7		"\xeb\x58\x90-FVE-FS-"
      55  #define BDE_MAGIC_TOGO		"\xeb\x58\x90MSWIN4.1"
      56  
      57  #define BDE_MAGIC_FVE		"-FVE-FS-"
      58  
      59  static int get_bitlocker_type(const unsigned char *buf)
      60  {
      61  	size_t i;
      62  	static const char *map[] = {
      63  		[BDE_VERSION_VISTA] = BDE_MAGIC_VISTA,
      64  		[BDE_VERSION_WIN7]  = BDE_MAGIC_WIN7,
      65  		[BDE_VERSION_TOGO]  = BDE_MAGIC_TOGO
      66  	};
      67  
      68  	for (i = 0; i < ARRAY_SIZE(map); i++) {
      69  		if (memcmp(buf, map[i], 11) == 0)
      70  			return (int) i;
      71  	}
      72  
      73  	return -1;
      74  }
      75  
      76  /* Returns: < 0 error, 1 nothing, 0 success
      77   */
      78  static int get_bitlocker_headers(blkid_probe pr,
      79  				int *type,
      80  				const unsigned char **buf_hdr,
      81  				const unsigned char **buf_fve)
      82  {
      83  
      84  	const unsigned char *buf;
      85  	const struct bde_fve_metadata *fve;
      86  	uint64_t off = 0;
      87  	int kind;
      88  
      89  	if (buf_hdr)
      90  		*buf_hdr = NULL;
      91  	if (buf_fve)
      92  		*buf_fve = NULL;
      93  	if (type)
      94  		*type = -1;
      95  
      96  	buf = blkid_probe_get_buffer(pr, BDE_HDR_OFFSET, BDE_HDR_SIZE);
      97  	if (!buf)
      98  		return errno ? -errno : 1;
      99  
     100  	kind = get_bitlocker_type(buf);
     101  
     102  	/* Check BitLocker header */
     103  	switch (kind) {
     104  	case BDE_VERSION_WIN7:
     105  		off = le64_to_cpu(((const struct bde_header_win7 *) buf)->fve_metadata_offset);
     106  		break;
     107  	case BDE_VERSION_TOGO:
     108  		off = le64_to_cpu(((const struct bde_header_togo *) buf)->fve_metadata_offset);
     109  		break;
     110  	case BDE_VERSION_VISTA:
     111  		goto done;
     112  	default:
     113  		goto nothing;
     114  	}
     115  
     116  	if (!off || off % 64)
     117  		goto nothing;
     118  	if (buf_hdr)
     119  		*buf_hdr = buf;
     120  
     121  	/* Check Bitlocker FVE metadata header */
     122  	buf = blkid_probe_get_buffer(pr, off, sizeof(struct bde_fve_metadata));
     123  	if (!buf)
     124  		return errno ? -errno : 1;
     125  
     126  	fve = (const struct bde_fve_metadata *) buf;
     127  	if (memcmp(fve->signature, BDE_MAGIC_FVE, sizeof(fve->signature)) != 0)
     128  		goto nothing;
     129  	if (buf_fve)
     130  		*buf_fve = buf;
     131  done:
     132  	if (type)
     133  		*type = kind;
     134  	return 0;
     135  nothing:
     136  	return 1;
     137  }
     138  
     139  /*
     140   * This is used by vFAT and NTFS prober to avoid collisions with bitlocker.
     141   */
     142  int blkid_probe_is_bitlocker(blkid_probe pr)
     143  {
     144  	return get_bitlocker_headers(pr, NULL, NULL, NULL) == 0;
     145  }
     146  
     147  static int probe_bitlocker(blkid_probe pr,
     148  		const struct blkid_idmag *mag __attribute__((__unused__)))
     149  {
     150  	const unsigned char *buf_fve = NULL;
     151  	const unsigned char *buf_hdr = NULL;
     152  	int rc, kind;
     153  
     154  	rc = get_bitlocker_headers(pr, &kind, &buf_hdr, &buf_fve);
     155  	if (rc)
     156  		return rc;
     157  
     158  	if (kind == BDE_VERSION_WIN7) {
     159  		const struct bde_header_win7 *hdr = (const struct bde_header_win7 *) buf_hdr;
     160  
     161  		/* Unfortunately, it seems volume_serial is always zero */
     162  		blkid_probe_sprintf_uuid(pr,
     163  				(const unsigned char *) &hdr->volume_serial,
     164  				sizeof(hdr->volume_serial),
     165  				"%016d", le32_to_cpu(hdr->volume_serial));
     166  	}
     167  
     168  	if (buf_fve) {
     169  		const struct bde_fve_metadata *fve = (const struct bde_fve_metadata *) buf_fve;
     170  
     171  		blkid_probe_sprintf_version(pr, "%d", fve->version);
     172  	}
     173  	return 0;
     174  }
     175  
     176  /* See header details:
     177   * https://github.com/libyal/libbde/blob/master/documentation/BitLocker%20Drive%20Encryption%20(BDE)%20format.asciidoc
     178   */
     179  const struct blkid_idinfo bitlocker_idinfo =
     180  {
     181  	.name		= "BitLocker",
     182  	.usage		= BLKID_USAGE_CRYPTO,
     183  	.probefunc	= probe_bitlocker,
     184  	.magics		=
     185  	{
     186  		{ .magic = BDE_MAGIC_VISTA, .len = 11 },
     187  		{ .magic = BDE_MAGIC_WIN7,  .len = 11 },
     188  		{ .magic = BDE_MAGIC_TOGO,  .len = 11 },
     189  		{ NULL }
     190  	}
     191  };