Decode windows TPM/PCP errors to more specific descriptions. (#28)

This commit is contained in:
Tom D 2019-05-14 11:42:44 -07:00 committed by GitHub
parent ac78180218
commit 55ce06b8f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -63,6 +63,10 @@ var (
tpm32 = windows.MustLoadDLL("Win32_tpm.dll") tpm32 = windows.MustLoadDLL("Win32_tpm.dll")
tpm32IsReadyInformation = tpm32.MustFindProc("IsReadyInformation") tpm32IsReadyInformation = tpm32.MustFindProc("IsReadyInformation")
)
// Error codes.
var (
isReadyErrors = map[uint32]string{ isReadyErrors = map[uint32]string{
0x00000002: "Platform restart is required (shutdown).", 0x00000002: "Platform restart is required (shutdown).",
0x00000004: "Platform restart is required (reboot).", 0x00000004: "Platform restart is required (reboot).",
@ -84,8 +88,146 @@ var (
0x00400000: "The device lock counter has not been created.", 0x00400000: "The device lock counter has not been created.",
0x00800000: "The device identifier has not been created.", 0x00800000: "The device identifier has not been created.",
} }
tpmErrNums = map[uint32]string{
0x80280001: "TPM_E_AUTHFAIL",
0x80280002: "TPM_E_BADINDEX",
0x80280003: "TPM_E_BAD_PARAMETER",
0x80280004: "TPM_E_AUDITFAILURE",
0x80280005: "TPM_E_CLEAR_DISABLED",
0x80280006: "TPM_E_DEACTIVATED",
0x80280007: "TPM_E_DISABLED",
0x80280008: "TPM_E_DISABLED_CMD",
0x80280009: "TPM_E_FAIL",
0x8028000A: "TPM_E_BAD_ORDINAL",
0x8028000B: "TPM_E_INSTALL_DISABLED",
0x8028000C: "TPM_E_INVALID_KEYHANDLE",
0x8028000D: "TPM_E_KEYNOTFOUND",
0x8028000E: "TPM_E_INAPPROPRIATE_ENC",
0x8028000F: "TPM_E_MIGRATEFAIL",
0x80280010: "TPM_E_INVALID_PCR_INFO",
0x80280011: "TPM_E_NOSPACE",
0x80280012: "TPM_E_NOSRK",
0x80280013: "TPM_E_NOTSEALED_BLOB",
0x80280014: "TPM_E_OWNER_SET",
0x80280015: "TPM_E_RESOURCES",
0x80280016: "TPM_E_SHORTRANDOM",
0x80280017: "TPM_E_SIZE",
0x80280018: "TPM_E_WRONGPCRVAL",
0x80280019: "TPM_E_BAD_PARAM_SIZE",
0x8028001A: "TPM_E_SHA_THREAD",
0x8028001B: "TPM_E_SHA_ERROR",
0x8028001C: "TPM_E_FAILEDSELFTEST",
0x8028001D: "TPM_E_AUTH2FAIL",
0x8028001E: "TPM_E_BADTAG",
0x8028001F: "TPM_E_IOERROR",
0x80280020: "TPM_E_ENCRYPT_ERROR",
0x80280021: "TPM_E_DECRYPT_ERROR",
0x80280022: "TPM_E_INVALID_AUTHHANDLE",
0x80280023: "TPM_E_NO_ENDORSEMENT",
0x80280024: "TPM_E_INVALID_KEYUSAGE",
0x80280025: "TPM_E_WRONG_ENTITYTYPE",
0x80280026: "TPM_E_INVALID_POSTINIT",
0x80280027: "TPM_E_INAPPROPRIATE_SIG",
0x80280028: "TPM_E_BAD_KEY_PROPERTY",
0x80280029: "TPM_E_BAD_MIGRATION",
0x8028002A: "TPM_E_BAD_SCHEME",
0x8028002B: "TPM_E_BAD_DATASIZE",
0x8028002C: "TPM_E_BAD_MODE",
0x8028002D: "TPM_E_BAD_PRESENCE",
0x8028002E: "TPM_E_BAD_VERSION",
0x8028002F: "TPM_E_NO_WRAP_TRANSPORT",
0x80280030: "TPM_E_AUDITFAIL_UNSUCCESSFUL",
0x80280031: "TPM_E_AUDITFAIL_SUCCESSFUL",
0x80280032: "TPM_E_NOTRESETABLE",
0x80280033: "TPM_E_NOTLOCAL",
0x80280034: "TPM_E_BAD_TYPE",
0x80280035: "TPM_E_INVALID_RESOURCE",
0x80280036: "TPM_E_NOTFIPS",
0x80280037: "TPM_E_INVALID_FAMILY",
0x80280038: "TPM_E_NO_NV_PERMISSION",
0x80280039: "TPM_E_REQUIRES_SIGN",
0x8028003A: "TPM_E_KEY_NOTSUPPORTED",
0x8028003B: "TPM_E_AUTH_CONFLICT",
0x8028003C: "TPM_E_AREA_LOCKED",
// TODO: Finish NVRAM error codes.
0x80280049: "TPM_E_NOOPERATOR",
0x8028004A: "TPM_E_RESOURCEMISSING",
0x8028004B: "TPM_E_DELEGATE_LOCK",
0x8028004C: "TPM_E_DELEGATE_FAMILY",
0x8028004D: "TPM_E_DELEGATE_ADMIN",
0x8028004E: "TPM_E_TRANSPORT_NOTEXCLUSIVE",
0x8028004F: "TPM_E_OWNER_CONTROL",
0x80280050: "TPM_E_DAA_RESOURCES",
// TODO: Finish DAA error codes.
0x80280058: "TPM_E_BAD_HANDLE",
0x80280059: "TPM_E_BAD_DELEGATE",
0x8028005A: "TPM_E_BADCONTEXT",
0x8028005B: "TPM_E_TOOMANYCONTEXTS",
0x8028005C: "TPM_E_MA_TICKET_SIGNATURE",
0x8028005D: "TPM_E_MA_DESTINATION",
0x8028005E: "TPM_E_MA_SOURCE",
0x8028005F: "TPM_E_MA_AUTHORITY",
0x80280061: "TPM_E_PERMANENTEK",
0x80280062: "TPM_E_BAD_SIGNATURE",
0x80280063: "TPM_E_NOCONTEXTSPACE",
0x80280400: "TPM_E_COMMAND_BLOCKED",
0x80280401: "TPM_E_INVALID_HANDLE",
0x80280402: "TPM_E_DUPLICATE_VHANDLE",
0x80280403: "TPM_E_EMBEDDED_COMMAND_BLOCKED",
0x80280404: "TPM_E_EMBEDDED_COMMAND_UNSUPPORTED",
0x80280800: "TPM_E_RETRY",
0x80280801: "TPM_E_NEEDS_SELFTEST",
0x80280802: "TPM_E_DOING_SELFTEST",
0x80280803: "TPM_E_DEFEND_LOCK_RUNNING",
0x80284001: "TBS_E_INTERNAL_ERROR",
0x80284002: "TBS_E_BAD_PARAMETER",
0x80284003: "TBS_E_INVALID_OUTPUT_POINTER",
0x80284004: "TBS_E_INVALID_CONTEXT",
0x80284005: "TBS_E_INSUFFICIENT_BUFFER",
0x80284006: "TBS_E_IOERROR",
0x80284007: "TBS_E_INVALID_CONTEXT_PARAM",
0x80284008: "TBS_E_SERVICE_NOT_RUNNING",
0x80284009: "TBS_E_TOO_MANY_TBS_CONTEXTS",
0x8028400A: "TBS_E_TOO_MANY_RESOURCES",
0x8028400B: "TBS_E_SERVICE_START_PENDING",
0x8028400C: "TBS_E_PPI_NOT_SUPPORTED",
0x8028400D: "TBS_E_COMMAND_CANCELED",
0x8028400E: "TBS_E_BUFFER_TOO_LARGE",
0x8028400F: "TBS_E_TPM_NOT_FOUND",
0x80284010: "TBS_E_SERVICE_DISABLED",
0x80284011: "TBS_E_NO_EVENT_LOG",
0x80284012: "TBS_E_ACCESS_DENIED",
0x80284013: "TBS_E_PROVISIONING_NOT_ALLOWED",
0x80284014: "TBS_E_PPI_FUNCTION_UNSUPPORTED",
0x80284015: "TBS_E_OWNERAUTH_NOT_FOUND",
0x80284016: "TBS_E_PROVISIONING_INCOMPLETE",
// TODO: TPMAPI & TPMSIMP error codes.
0x80290401: "TPM_E_PCP_DEVICE_NOT_READY",
0x80290402: "TPM_E_PCP_INVALID_HANDLE",
0x80290403: "TPM_E_PCP_INVALID_PARAMETER",
0x80290404: "TPM_E_PCP_FLAG_NOT_SUPPORTED",
0x80290405: "TPM_E_PCP_NOT_SUPPORTED",
0x80290406: "TPM_E_PCP_BUFFER_TOO_SMALL",
0x80290407: "TPM_E_PCP_INTERNAL_ERROR",
0x80290408: "TPM_E_PCP_AUTHENTICATION_FAILED",
0x80290409: "TPM_E_PCP_AUTHENTICATION_IGNORED",
0x8029040A: "TPM_E_PCP_POLICY_NOT_FOUND",
0x8029040B: "TPM_E_PCP_PROFILE_NOT_FOUND",
0x8029040C: "TPM_E_PCP_VALIDATION_FAILED",
}
) )
func maybeWinErr(err error) error {
errno, ok := err.(*syscall.Errno)
if !ok {
return nil
}
if code, known := tpmErrNums[uint32(*errno)]; known {
return fmt.Errorf("tpm or subsystem failure: %s", code)
}
return nil
}
func queryTPMState() (bool, error) { func queryTPMState() (bool, error) {
var ( var (
isReady bool isReady bool
@ -126,6 +268,9 @@ func utf16ToString(buf []byte) (string, error) {
func closeNCryptObject(hnd uintptr) error { func closeNCryptObject(hnd uintptr) error {
r, _, msg := nCryptFreeObject.Call(hnd) r, _, msg := nCryptFreeObject.Call(hnd)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(msg); tpmErr != nil {
return tpmErr
}
return fmt.Errorf("NCryptFreeObject returned %X: %v", r, msg) return fmt.Errorf("NCryptFreeObject returned %X: %v", r, msg)
} }
return nil return nil
@ -142,11 +287,17 @@ func getNCryptBufferProperty(hnd uintptr, field string) ([]byte, error) {
r, _, msg := nCryptGetProperty.Call(hnd, uintptr(unsafe.Pointer(&wideField[0])), 0, 0, uintptr(unsafe.Pointer(&size)), 0) r, _, msg := nCryptGetProperty.Call(hnd, uintptr(unsafe.Pointer(&wideField[0])), 0, 0, uintptr(unsafe.Pointer(&size)), 0)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(msg); tpmErr != nil {
msg = tpmErr
}
return nil, fmt.Errorf("NCryptGetProperty returned %d,%X (%v) for key %q on size read", size, r, msg, field) return nil, fmt.Errorf("NCryptGetProperty returned %d,%X (%v) for key %q on size read", size, r, msg, field)
} }
buff := make([]byte, size) buff := make([]byte, size)
r, _, msg = nCryptGetProperty.Call(hnd, uintptr(unsafe.Pointer(&wideField[0])), uintptr(unsafe.Pointer(&buff[0])), uintptr(size), uintptr(unsafe.Pointer(&size)), 0) r, _, msg = nCryptGetProperty.Call(hnd, uintptr(unsafe.Pointer(&wideField[0])), uintptr(unsafe.Pointer(&buff[0])), uintptr(size), uintptr(unsafe.Pointer(&size)), 0)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(msg); tpmErr != nil {
msg = tpmErr
}
return nil, fmt.Errorf("NCryptGetProperty returned %X (%v) for key %q on data read", r, msg, field) return nil, fmt.Errorf("NCryptGetProperty returned %X (%v) for key %q on data read", r, msg, field)
} }
return buff, nil return buff, nil
@ -215,6 +366,9 @@ func (h *winPCP) TPMCommandInterface() (io.ReadWriteCloser, error) {
r, _, err := nCryptGetProperty.Call(h.hProv, uintptr(unsafe.Pointer(&platformHndField[0])), uintptr(unsafe.Pointer(&provTBS)), unsafe.Sizeof(provTBS), uintptr(unsafe.Pointer(&sz)), 0) r, _, err := nCryptGetProperty.Call(h.hProv, uintptr(unsafe.Pointer(&platformHndField[0])), uintptr(unsafe.Pointer(&provTBS)), unsafe.Sizeof(provTBS), uintptr(unsafe.Pointer(&sz)), 0)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(err); tpmErr != nil {
err = tpmErr
}
return nil, fmt.Errorf("NCryptGetProperty for platform handle returned %X (%v)", r, err) return nil, fmt.Errorf("NCryptGetProperty for platform handle returned %X (%v)", r, err)
} }
@ -231,6 +385,9 @@ func (h *winPCP) TPMKeyHandle(hnd uintptr) (tpmutil.Handle, error) {
} }
if r, _, err := nCryptGetProperty.Call(hnd, uintptr(unsafe.Pointer(&platformHndField[0])), uintptr(unsafe.Pointer(&keyHndTBS)), unsafe.Sizeof(keyHndTBS), uintptr(unsafe.Pointer(&sz)), 0); r != 0 { if r, _, err := nCryptGetProperty.Call(hnd, uintptr(unsafe.Pointer(&platformHndField[0])), uintptr(unsafe.Pointer(&keyHndTBS)), unsafe.Sizeof(keyHndTBS), uintptr(unsafe.Pointer(&sz)), 0); r != 0 {
if tpmErr := maybeWinErr(err); tpmErr != nil {
err = tpmErr
}
return 0, fmt.Errorf("NCryptGetProperty for hKey platform handle returned %X (%v)", r, err) return 0, fmt.Errorf("NCryptGetProperty for hKey platform handle returned %X (%v)", r, err)
} }
@ -330,6 +487,9 @@ func (h *winPCP) MintAIK(name string) (uintptr, error) {
// Create a persistent RSA key of the specified name. // Create a persistent RSA key of the specified name.
r, _, msg := nCryptCreatePersistedKey.Call(h.hProv, uintptr(unsafe.Pointer(&kh)), uintptr(unsafe.Pointer(&utf16RSA[0])), uintptr(unsafe.Pointer(&utf16Name[0])), 0, 0) r, _, msg := nCryptCreatePersistedKey.Call(h.hProv, uintptr(unsafe.Pointer(&kh)), uintptr(unsafe.Pointer(&utf16RSA[0])), uintptr(unsafe.Pointer(&utf16Name[0])), 0, 0)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(msg); tpmErr != nil {
msg = tpmErr
}
return 0, fmt.Errorf("NCryptCreatePersistedKey returned %X: %v", r, msg) return 0, fmt.Errorf("NCryptCreatePersistedKey returned %X: %v", r, msg)
} }
// Specify generated key length to be 2048 bits. // Specify generated key length to be 2048 bits.
@ -340,6 +500,9 @@ func (h *winPCP) MintAIK(name string) (uintptr, error) {
var length uint32 = 2048 var length uint32 = 2048
r, _, msg = nCryptSetProperty.Call(kh, uintptr(unsafe.Pointer(&utf16Length[0])), uintptr(unsafe.Pointer(&length)), unsafe.Sizeof(length), 0) r, _, msg = nCryptSetProperty.Call(kh, uintptr(unsafe.Pointer(&utf16Length[0])), uintptr(unsafe.Pointer(&length)), unsafe.Sizeof(length), 0)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(msg); tpmErr != nil {
msg = tpmErr
}
return 0, fmt.Errorf("NCryptSetProperty (Length) returned %X: %v", r, msg) return 0, fmt.Errorf("NCryptSetProperty (Length) returned %X: %v", r, msg)
} }
// Specify the generated key can only be used for identity attestation. // Specify the generated key can only be used for identity attestation.
@ -350,12 +513,18 @@ func (h *winPCP) MintAIK(name string) (uintptr, error) {
var policy uint32 = nCryptPropertyPCPKeyUsagePolicyIdentity var policy uint32 = nCryptPropertyPCPKeyUsagePolicyIdentity
r, _, msg = nCryptSetProperty.Call(kh, uintptr(unsafe.Pointer(&utf16KeyPolicy[0])), uintptr(unsafe.Pointer(&policy)), unsafe.Sizeof(policy), 0) r, _, msg = nCryptSetProperty.Call(kh, uintptr(unsafe.Pointer(&utf16KeyPolicy[0])), uintptr(unsafe.Pointer(&policy)), unsafe.Sizeof(policy), 0)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(msg); tpmErr != nil {
msg = tpmErr
}
return 0, fmt.Errorf("NCryptSetProperty (PCP KeyUsage Policy) returned %X: %v", r, msg) return 0, fmt.Errorf("NCryptSetProperty (PCP KeyUsage Policy) returned %X: %v", r, msg)
} }
// Finalize (create) the key. // Finalize (create) the key.
r, _, msg = nCryptFinalizeKey.Call(kh, 0) r, _, msg = nCryptFinalizeKey.Call(kh, 0)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(msg); tpmErr != nil {
msg = tpmErr
}
return 0, fmt.Errorf("NCryptFinalizeKey returned %X: %v", r, msg) return 0, fmt.Errorf("NCryptFinalizeKey returned %X: %v", r, msg)
} }
@ -506,6 +675,9 @@ func (h *winPCP) ActivateCredential(hKey uintptr, activationBlob []byte) ([]byte
r, _, msg := nCryptSetProperty.Call(hKey, uintptr(unsafe.Pointer(&utf16ActivationStr[0])), uintptr(unsafe.Pointer(&activationBlob[0])), uintptr(len(activationBlob)), 0) r, _, msg := nCryptSetProperty.Call(hKey, uintptr(unsafe.Pointer(&utf16ActivationStr[0])), uintptr(unsafe.Pointer(&activationBlob[0])), uintptr(len(activationBlob)), 0)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(msg); tpmErr != nil {
msg = tpmErr
}
return nil, fmt.Errorf("NCryptSetProperty returned %X (%v) for key activation", r, msg) return nil, fmt.Errorf("NCryptSetProperty returned %X (%v) for key activation", r, msg)
} }
@ -513,6 +685,9 @@ func (h *winPCP) ActivateCredential(hKey uintptr, activationBlob []byte) ([]byte
var size uint32 var size uint32
r, _, msg = nCryptGetProperty.Call(hKey, uintptr(unsafe.Pointer(&utf16ActivationStr[0])), uintptr(unsafe.Pointer(&secretBuff[0])), uintptr(len(secretBuff)), uintptr(unsafe.Pointer(&size)), 0) r, _, msg = nCryptGetProperty.Call(hKey, uintptr(unsafe.Pointer(&utf16ActivationStr[0])), uintptr(unsafe.Pointer(&secretBuff[0])), uintptr(len(secretBuff)), uintptr(unsafe.Pointer(&size)), 0)
if r != 0 { if r != 0 {
if tpmErr := maybeWinErr(msg); tpmErr != nil {
msg = tpmErr
}
return nil, fmt.Errorf("NCryptGetProperty returned %X (%v) for key activation", r, msg) return nil, fmt.Errorf("NCryptGetProperty returned %X (%v) for key activation", r, msg)
} }
return secretBuff[:size], nil return secretBuff[:size], nil
@ -530,6 +705,9 @@ func openPCP() (*winPCP, error) {
r, _, err := nCryptOpenStorageProvider.Call(uintptr(unsafe.Pointer(&h.hProv)), uintptr(unsafe.Pointer(&pname[0])), 0) r, _, err := nCryptOpenStorageProvider.Call(uintptr(unsafe.Pointer(&h.hProv)), uintptr(unsafe.Pointer(&pname[0])), 0)
if r != 0 { // r is non-zero on error, err is always populated in this case. if r != 0 { // r is non-zero on error, err is always populated in this case.
if tpmErr := maybeWinErr(err); tpmErr != nil {
return nil, tpmErr
}
return nil, err return nil, err
} }
return &h, nil return &h, nil