go.mondoo.com/cnquery@v0.0.0-20231005093811-59568235f6ea/providers/os/resources/windows/bitlocker.go (about)

     1  // Copyright (c) Mondoo, Inc.
     2  // SPDX-License-Identifier: BUSL-1.1
     3  
     4  package windows
     5  
     6  import (
     7  	"encoding/json"
     8  	"io"
     9  
    10  	"go.mondoo.com/cnquery/providers/os/connection/shared"
    11  	"go.mondoo.com/cnquery/providers/os/resources/powershell"
    12  )
    13  
    14  // https://docs.microsoft.com/en-us/windows/win32/secprov/getconversionstatus-win32-encryptablevolume
    15  var conversionStatusValues = map[int64]string{
    16  	0: "FullyDecrypted",
    17  	1: "FullyEncrypted",
    18  	2: "EncryptionInProgress",
    19  	3: "DecryptionInProgress",
    20  	4: "EncryptionPaused",
    21  	5: "DecryptionPaused",
    22  }
    23  
    24  // https://docs.microsoft.com/en-us/windows/win32/secprov/getconversionstatus-win32-encryptablevolume
    25  var wipingStatusValues = map[int64]string{
    26  	0: "FreeSpaceNotWiped",
    27  	1: "FreeSpaceWiped",
    28  	2: "FreeSpaceWipingInProgress",
    29  	3: "FreeSpaceWipingPaused",
    30  }
    31  
    32  // https://docs.microsoft.com/en-us/windows/win32/secprov/getencryptionmethod-win32-encryptablevolume
    33  var encryptionMethodValues = map[int64]string{
    34  	0: "NONE",
    35  	1: "AES_128_WITH_DIFFUSER",
    36  	2: "AES_256_WITH_DIFFUSER",
    37  	3: "AES_128",
    38  	4: "AES_256",
    39  	5: "HARDWARE_ENCRYPTION",
    40  	6: "XTS_AES_128",
    41  	7: "XTS_AES_256",
    42  }
    43  
    44  var fveVersionValues = map[int64]string{
    45  	0: "Unknown",
    46  	1: "Vista",
    47  	2: "Win7",
    48  }
    49  
    50  // https://docs.microsoft.com/en-us/windows/win32/secprov/getprotectionstatus-win32-encryptablevolume
    51  var protectionStatusValues = map[int64]string{
    52  	0: "Unprotected",
    53  	1: "Protected",
    54  	2: "Unknown",
    55  }
    56  
    57  const bitlockerStatusScript = `
    58  $encryptedVolumes = Get-WmiObject -namespace "Root\cimv2\security\MicrosoftVolumeEncryption" -ClassName "Win32_Encryptablevolume" 
    59  
    60  $bitlockerStatus = @()
    61  
    62  foreach ($volume in $encryptedVolumes) {
    63  	
    64  	$wmiVersion = $volume.GetVersion()
    65  	$version = New-Object psobject -Property @{
    66  	  "Version" =  $wmiVersion.Version;
    67  	}
    68  	
    69  	$wmiConversionStatus = $volume.GetConversionStatus()
    70  	$conversionStatus = New-Object psobject -Property @{
    71  	  "ConversionStatus" =  $wmiConversionStatus.ConversionStatus;
    72  	  "EncryptionFlags" =  $wmiConversionStatus.EncryptionFlags;
    73  	  "EncryptionPercentage" =  $wmiConversionStatus.EncryptionPercentage;
    74  	  "WipingPercentage"  = $wmiConversionStatus.WipingPercentage;
    75  	  "WipingStatus"  = $wmiConversionStatus.WipingStatus;
    76  	}
    77  	
    78  	$wmilockStatus = $volume.GetLockStatus()
    79  	$lockStatus = New-Object psobject -Property @{
    80  	  "LockStatus" =  $wmilockStatus.LockStatus;
    81  	}
    82  	
    83  	$volumeStatus = New-Object PSObject
    84  	Add-Member -InputObject $volumeStatus -MemberType NoteProperty -Name volume -Value $volume
    85  	Add-Member -InputObject $volumeStatus -MemberType NoteProperty -Name version -Value $version
    86  	Add-Member -InputObject $volumeStatus -MemberType NoteProperty -Name conversionStatus -Value $conversionStatus
    87  	Add-Member -InputObject $volumeStatus -MemberType NoteProperty -Name lockStatus -Value $lockStatus
    88  	$bitlockerStatus = $bitlockerStatus + $volumeStatus
    89  }
    90  ConvertTo-Json -Depth 3 -Compress $bitlockerStatus
    91  `
    92  
    93  // powershellBitlockerVolumeStatus is the struct to parse the powershell result
    94  type powershellBitlockerVolumeStatus struct {
    95  	Volume struct {
    96  		ConversionStatus                 int64
    97  		DeviceID                         string
    98  		DriveLetter                      string
    99  		EncryptionMethod                 int64
   100  		IsVolumeInitializedForProtection bool
   101  		PersistentVolumeID               string
   102  		ProtectionStatus                 int64
   103  		VolumeType                       int64
   104  	}
   105  	Version struct {
   106  		Version int64
   107  	}
   108  	ConversionStatus struct {
   109  		ConversionStatus     int64
   110  		WipingStatus         int64
   111  		WipingPercentage     int64
   112  		EncryptionFlags      int64
   113  		EncryptionPercentage int64
   114  	}
   115  	LockStatus struct {
   116  		LockStatus int64
   117  	}
   118  }
   119  
   120  // bitlockerVolumeStatus returns the status for one individual volume
   121  type bitlockerVolumeStatus struct {
   122  	DeviceID           string
   123  	DriveLetter        string
   124  	ConversionStatus   conversionStatus
   125  	EncryptionMethod   statusCode
   126  	LockStatus         int64
   127  	PersistentVolumeID string
   128  	ProtectionStatus   statusCode
   129  	Version            statusCode
   130  }
   131  
   132  type conversionStatus struct {
   133  	ConversionStatus     statusCode
   134  	WipingStatus         statusCode
   135  	WipingPercentage     int64
   136  	EncryptionPercentage int64
   137  }
   138  
   139  type statusCode struct {
   140  	Code int64  `json:"code"`
   141  	Text string `json:"text"`
   142  }
   143  
   144  func GetBitLockerVolumes(p shared.Connection) ([]bitlockerVolumeStatus, error) {
   145  	c, err := p.RunCommand(powershell.Encode(bitlockerStatusScript))
   146  	if err != nil {
   147  		return nil, err
   148  	}
   149  
   150  	return ParseWindowsBitlockerStatus(c.Stdout)
   151  }
   152  
   153  func ParseWindowsBitlockerStatus(r io.Reader) ([]bitlockerVolumeStatus, error) {
   154  	var volumeStatus []powershellBitlockerVolumeStatus
   155  	data, err := io.ReadAll(r)
   156  	if err != nil {
   157  		return nil, err
   158  	}
   159  
   160  	err = json.Unmarshal(data, &volumeStatus)
   161  	if err != nil {
   162  		return nil, err
   163  	}
   164  
   165  	res := []bitlockerVolumeStatus{}
   166  	for i := range volumeStatus {
   167  		v := volumeStatus[i]
   168  
   169  		bvs := bitlockerVolumeStatus{
   170  			DeviceID:    v.Volume.DeviceID,
   171  			DriveLetter: v.Volume.DriveLetter,
   172  			ConversionStatus: conversionStatus{
   173  				ConversionStatus: statusCode{
   174  					Code: v.ConversionStatus.ConversionStatus,
   175  					Text: conversionStatusValues[v.ConversionStatus.ConversionStatus],
   176  				},
   177  				EncryptionPercentage: v.ConversionStatus.EncryptionPercentage,
   178  				WipingStatus: statusCode{
   179  					Code: v.ConversionStatus.WipingStatus,
   180  					Text: wipingStatusValues[v.ConversionStatus.WipingStatus],
   181  				},
   182  				WipingPercentage: v.ConversionStatus.WipingPercentage,
   183  			},
   184  			EncryptionMethod: statusCode{
   185  				Code: v.Volume.EncryptionMethod,
   186  				Text: encryptionMethodValues[v.Volume.EncryptionMethod],
   187  			},
   188  			LockStatus:         v.LockStatus.LockStatus,
   189  			PersistentVolumeID: v.Volume.PersistentVolumeID,
   190  			ProtectionStatus: statusCode{
   191  				Code: v.Volume.ProtectionStatus,
   192  				Text: protectionStatusValues[v.Volume.ProtectionStatus],
   193  			},
   194  			Version: statusCode{
   195  				Code: v.Version.Version,
   196  				Text: fveVersionValues[v.Version.Version],
   197  			},
   198  		}
   199  		res = append(res, bvs)
   200  	}
   201  	return res, nil
   202  }