DRAFT: Take more than your usual care.

SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION

The SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION structure is what a successful call to ZwQuerySystemInformation or NtQuerySystemInformation produces in its output buffer when given the information class SystemSecureBootPolicyFullInformation (0xAB).

Documentation Status

The SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION structure is not documented.

Layout

Formally, the SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION is 0x20 bytes in both 32-bit and 64-bit Windows. In practice, it is a fixed-size header of 0x1C bytes plus a variable-size Policy whose size in bytes is given by PolicySize in the header.

Offset Definition
0x00
SYSTEM_SECUREBOOT_POLICY_INFORMATION PolicyInformation;
0x18
ULONG PolicySize;
0x1C
UCHAR Policy [ANYSIZE_ARRAY];

The Secure Boot Policy Blob

As far as concerns the ZwQuerySystemInformation function and the SYSTEM_SECUREBOOT_POLICY_FULL_INFORMATION structure, the Policy is an opaque blob. The kernel will have received the blob from the loader, else the function has nothing to return. The kernel interprets some of the contents, but relies on parsing that is also received from the loader. In the possibly temporary absence of somewhere better, the blob’s interpretation is as well given here. No formal structure is known. The loader parses it as a stream. In the original release of version 10.0, this parsing picks out the following sequence of items:

  1. a word, which can be no greater than 2;
  2. a dword, which is the PolicyVersion;
  3. a GUID, which is the PolicyPublisher;
  4. a one-word count, which may be zero, for a GUID array that follows;
  5. the possibly empty GUID array;
  6. a dword, which is the PolicyOptions;
  7. a one-word count, which may be zero, of BCD rules that come later;
  8. a one-word count, which may be zero, of registry rules that come later;
  9. the BCD rules, as a possibly empty array of 0x0C-byte structures;
  10. the registry rules, as a possibly empty array of 0x10-byte structures;
  11. value table, as whatever remains in the policy blob.

The terms BCD rule, registry rule and value table are surmised from the names of relevant routines as known from public symbol files for the loader and kernel.

The least size for a valid Secure Boot Policy blob is 0x20 bytes, being 0x18 bytes for the first four items as a fixed-size header, plus the PolicyOptions and two counts, with all variable-size items empty.

Boot Configuration Data (BCD) Rule

Each BCD rule describes the policy expectations of one boot option:

Offset Size Description
0x00 dword BCD object type in which option is subject to rule;
else zero if option is subject to rule in any BCD object
0x04 dword BCD element type
0x08 dword offset into value table of value table entry

Remember that each boot option is a BCD element in a BCD object. The same numerical value for a BCD element can be defined for multiple BCD objects yet denote completely unrelated boot options. For instance, the element type 0x23000003 is default in a Windows Boot Manager object (with object type 0x10200001) but resumeobject in a Windows Boot Loader object (with object type 0x10200003). Were a rule to have zero for the object type and 0x23000003 as the element type, then it would apply to both default and resumeobject in all BCD objects.

If a rule specifies a BCD object, then it applies only to that precise combination of BCD object and BCD element. Suppose, for instance, that a BCD rule would prevent the setting of the debug option (element type 0x260000A0) in BCD objects of type 0x10200003. Then the kernel’s enforcement of the policy does indeed mean that while Secure Boot is enabled the debug option can not be set in any Windows Boot Loader object such as created by the BCDEDIT command-line switches /create /application osloader and that the option will be deleted from all such objects if Secure Boot is later enabled. However, the rule does not prevent the option from being set in a {bootloadersettings} or {kerneldbgsettings} object. This is useful in practice because the latter types of object are inheritable by the former. Set the debug option in an inheritable object, and its effect is nullified by policy for the inheriting object while Secure Boot is enabled but because the option in the inherited object is not subject to policy, it is not deleted and it regains its effect if Secure Boot is later disabled.

Registry Rule

Each registry rule describes a key and value in a Secure Boot registry hive.

Offset Size Description
0x00 dword must be 0x81000000
0x04 dword offset into value table of registry key as sized string
0x08 dword offset into value table of registry value as sized string
0x0C dword offset into value table of value table entry

The registry key and value that the rule applies to are held in the value table as a one-word size in bytes of Unicode characters that follow. The characters end with a null that is not in the size.

Value Table Entry

The value table holds variable-size details for the rules. Some such details are counted strings, as described above for registry rules. Others are value table entries that each begin with a word of bit fields. The type, as masked by 0x1F, determines the value table entry’s layout beyond its first word.

Mask Description
0x001F type
0x0020 rule subject to BitLocker
0x0040 rule subject to Virtualization Based Security (VBS)

The precise conditions are meant above by BitLocker and VBS are beyond the present scope of this note.

A value table entry of type 0 defines a string value.

Offset Type Description
0x00 word flags; 0x00 as type
0x02 word size in bytes of string that follows, not including terminating null
0x04 word array default value as case-insensitive null-terminated Unicode string

Type 1 defines a boolean value.

Offset Type Description
0x00 word flags; 0x01 as type
0x02 word zero if default value is FALSE;
non-zero if default value is TRUE

Types 2 to 4 are for ULONG values. All these value types allow that a policy can force one value as the default, but the different types allow that the enforcement can be conditional. Type 2 is for a policy that insists on the one value unconditionally:

Offset Type Description
0x00 word flags; 0x02 as type
0x02 dword default value

Type 3 elaborates with a range of acceptable ULONG values:

Offset Type Description
0x00 word flags; 0x03 as type
0x02 dword default value
0x06 dword lowest acceptable value
0x0A dword highest acceptable value

For type 4 the elaboration of acceptable ULONG values is instead an enumeration:

Offset Type Description
0x00 word flags; 0x04 as type
0x02 dword default value
0x06 word count of acceptable values
0x08 dword array array of acceptable values

Types 5 to 7 are the same but for ULONGLONG values. Type 5 is the basic case of a single ULONGLONG value to enforce by policy:

Offset Size Description
0x00 word flags; 0x05 as type
0x02 qword default value

Type 6 defines the acceptable ULONGLONG values as a range:

Offset Size Description
0x00 word flags; 0x06 as type
0x02 qword default value
0x0A qword lowest acceptable value
0x12 qword highest acceptable value

Type 7 lists the acceptable ULONGLONG values as an array:

Offset Size Description
0x00 word flags; 0x07 as type
0x02 qword default value
0x0A word count of acceptable values
0x0C qword array array of acceptable values

For type 8, there is no default value to enforce. Instead, the policy is whether the BCD option or registry value is permitted at all. According to public symbols for the Boot Manager, this type of value table entry is an option.

Offset Type Description
0x00 word flags; 0x08 as type
0x02 word zero if not permitted;
else non-zero to preserve

If the second word is zero in this value table entry for a BCD rule, then the corresponding BCD option’s existence is a policy violation. The option cannot be set to any value while Secure Boot is enabled. It can be deleted, however. Indeed, any updating of the BCD store that is done when Secure Boot gets enabled is meant to delete the option. If the second word is non-zero, then not only does the rule allow the corresponding BCD option, it makes a policy violation of deleting it.

Type 9 is valid for a value table entry, but the only code that is yet known for interpreting it does no more than compute the size:

Offset Type Description
0x00 word flags; 0x09 as type
0x02   unknown two bytes
0x04 word size in bytes of data at offset 0x0A
0x06   unknown four bytes
0x0A   unknown data

Type 10 defines a binary value:

Offset Type Description
0x00 word flags; 0x0A as type
0x02 word size in bytes of data that follows
0x04 byte array default value