trousers: Add boundary check functions

Add some safe primitives for parsing TPM_DELEGATE_LABEL,
TPM_DELEGATIONS, TPM_DELEGATE_PUBLIC, TPM_DELEGATE_OWNER_BLOB...

BUG=b:169392230, b:233949215, b:174816474
TEST=Manually check Trspi_UnloadBlob_TPM_DELEGATE_OWNER_BLOB_s works

Change-Id: Ic695d75af47652b54c40ff4815fc7c0b761957ed
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/third_party/trousers/+/3669929
Tested-by: Yi Chou <yich@google.com>
Reviewed-by: Andrey Pronin <apronin@chromium.org>
Commit-Queue: Yi Chou <yich@google.com>
diff --git a/src/include/trousers/trousers.h b/src/include/trousers/trousers.h
index 83233d5..3dee970 100644
--- a/src/include/trousers/trousers.h
+++ b/src/include/trousers/trousers.h
@@ -81,9 +81,13 @@
 void       Trspi_UnloadBlob_TPM_FAMILY_LABEL(UINT64 *offset, BYTE *blob, TPM_FAMILY_LABEL *label);
 void       Trspi_UnloadBlob_TPM_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TPM_FAMILY_TABLE_ENTRY *entry);
 void       Trspi_UnloadBlob_TPM_DELEGATE_LABEL(UINT64 *offset, BYTE *blob, TPM_DELEGATE_LABEL *label);
+TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_LABEL_s(UINT64 *offset, BYTE *blob, UINT64 capacity, TPM_DELEGATE_LABEL *label);
 void       Trspi_UnloadBlob_TPM_DELEGATIONS(UINT64 *offset, BYTE *blob, TPM_DELEGATIONS *delegations);
+TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATIONS_s(UINT64 *offset, BYTE *blob, UINT64 capacity, TPM_DELEGATIONS *delegations);
 TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC(UINT64 *offset, BYTE *blob, TPM_DELEGATE_PUBLIC *pub);
+TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC_s(UINT64 *offset, BYTE *blob,  UINT64 capacity, TPM_DELEGATE_PUBLIC *pub);
 TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_OWNER_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_OWNER_BLOB *owner);
+TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_OWNER_BLOB_s(UINT64 *offset, BYTE *blob, UINT64 capacity, TPM_DELEGATE_OWNER_BLOB *owner);
 TSS_RESULT Trspi_UnloadBlob_TPM_DELEGATE_KEY_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_KEY_BLOB *key);
 void       Trspi_UnloadBlob_TSS_FAMILY_TABLE_ENTRY(UINT64 *offset, BYTE *blob, TSS_FAMILY_TABLE_ENTRY *entry);
 TSS_RESULT Trspi_UnloadBlob_TSS_PCR_INFO_SHORT(UINT64 *offset, BYTE *blob, TSS_PCR_INFO_SHORT *pcr);
diff --git a/src/trspi/trousers.c b/src/trspi/trousers.c
index dbfc715..10e57f8 100644
--- a/src/trspi/trousers.c
+++ b/src/trspi/trousers.c
@@ -2842,6 +2842,17 @@
 	Trspi_UnloadBlob_BYTE(offset, &label->label, blob);
 }
 
+TSS_RESULT
+Trspi_UnloadBlob_TPM_DELEGATE_LABEL_s(UINT64 *offset, BYTE *blob, UINT64 capacity, TPM_DELEGATE_LABEL *label)
+{
+	BYTE *internal_label = NULL;
+
+	if (label)
+		internal_label = &label->label;
+
+	return Trspi_UnloadBlob_BYTE_s(offset, internal_label, blob, capacity);
+}
+
 void
 Trspi_LoadBlob_TPM_DELEGATE_LABEL(UINT64 *offset, BYTE *blob, TPM_DELEGATE_LABEL *label)
 {
@@ -2866,6 +2877,36 @@
 	Trspi_UnloadBlob_UINT32(offset, &delegations->per2, blob);
 }
 
+TSS_RESULT
+Trspi_UnloadBlob_TPM_DELEGATIONS_s(UINT64 *offset, BYTE *blob, UINT64 capacity, TPM_DELEGATIONS *delegations)
+{
+	TSS_RESULT result;
+
+	if (!delegations) {
+		if ((result = Trspi_UnloadBlob_UINT16_s(offset, NULL, blob, capacity)))
+			return result;
+		if ((result = Trspi_UnloadBlob_UINT32_s(offset, NULL, blob, capacity)))
+			return result;
+		if ((result = Trspi_UnloadBlob_UINT32_s(offset, NULL, blob, capacity)))
+			return result;
+		if ((result = Trspi_UnloadBlob_UINT32_s(offset, NULL, blob, capacity)))
+			return result;
+
+		return TSS_SUCCESS;
+	}
+
+	if ((result = Trspi_UnloadBlob_UINT16_s(offset, &delegations->tag, blob, capacity)))
+		return result;
+	if ((result = Trspi_UnloadBlob_UINT32_s(offset, &delegations->delegateType, blob, capacity)))
+		return result;
+	if ((result = Trspi_UnloadBlob_UINT32_s(offset, &delegations->per1, blob, capacity)))
+		return result;
+	if ((result = Trspi_UnloadBlob_UINT32_s(offset, &delegations->per2, blob, capacity)))
+		return result;
+
+	return TSS_SUCCESS;
+}
+
 void
 Trspi_LoadBlob_TPM_DELEGATIONS(UINT64 *offset, BYTE *blob, TPM_DELEGATIONS *delegations)
 {
@@ -2902,6 +2943,55 @@
 	return TSS_SUCCESS;
 }
 
+TSS_RESULT
+Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC_s(UINT64 *offset, BYTE *blob, UINT64 capacity, TPM_DELEGATE_PUBLIC *pub)
+{
+	TSS_RESULT result;
+
+	if (!pub) {
+		if ((result = Trspi_UnloadBlob_UINT16_s(offset, NULL, blob, capacity)))
+			return result;
+		if ((result = Trspi_UnloadBlob_TPM_DELEGATE_LABEL_s(offset, blob, capacity, NULL)))
+			return result;
+		if ((result = Trspi_UnloadBlob_PCR_INFO_SHORT_s(offset, blob, capacity, NULL)))
+			return result;
+		if ((result = Trspi_UnloadBlob_TPM_DELEGATIONS_s(offset, blob, capacity, NULL)))
+			return result;
+		if ((result = Trspi_UnloadBlob_UINT32_s(offset, NULL, blob, capacity)))
+			return result;
+		if ((result = Trspi_UnloadBlob_UINT32_s(offset, NULL, blob, capacity)))
+			return result;
+
+		return TSS_SUCCESS;
+	}
+
+	if ((result = Trspi_UnloadBlob_UINT16_s(offset, &pub->tag, blob, capacity)))
+		return result;
+	if ((result = Trspi_UnloadBlob_TPM_DELEGATE_LABEL_s(offset, blob, capacity, &pub->label)))
+		return result;
+	if ((result = Trspi_UnloadBlob_PCR_INFO_SHORT_s(offset, blob, capacity, &pub->pcrInfo)))
+		return result;
+	if ((result = Trspi_UnloadBlob_TPM_DELEGATIONS_s(offset, blob, capacity, &pub->permissions))) {
+		free(pub->pcrInfo.pcrSelection.pcrSelect);
+		pub->pcrInfo.pcrSelection.sizeOfSelect = 0;
+		pub->pcrInfo.pcrSelection.pcrSelect = NULL;
+		return result;
+	}
+	if ((result = Trspi_UnloadBlob_UINT32_s(offset, &pub->familyID, blob, capacity))) {
+		free(pub->pcrInfo.pcrSelection.pcrSelect);
+		pub->pcrInfo.pcrSelection.sizeOfSelect = 0;
+		pub->pcrInfo.pcrSelection.pcrSelect = NULL;
+		return result;
+	}
+	if ((result = Trspi_UnloadBlob_UINT32_s(offset, &pub->verificationCount, blob, capacity))) {
+		free(pub->pcrInfo.pcrSelection.pcrSelect);
+		pub->pcrInfo.pcrSelection.sizeOfSelect = 0;
+		pub->pcrInfo.pcrSelection.pcrSelect = NULL;
+		return result;
+	}
+	return TSS_SUCCESS;
+}
+
 void
 Trspi_LoadBlob_TPM_DELEGATE_PUBLIC(UINT64 *offset, BYTE *blob, TPM_DELEGATE_PUBLIC *pub)
 {
@@ -2961,6 +3051,103 @@
 	return TSS_SUCCESS;
 }
 
+TSS_RESULT
+Trspi_UnloadBlob_TPM_DELEGATE_OWNER_BLOB_s(UINT64 *offset, BYTE *blob, UINT64 capacity, TPM_DELEGATE_OWNER_BLOB *owner)
+{
+	TSS_RESULT result;
+
+	if (!owner) {
+		UINT32 additionalSize, sensitiveSize;
+
+		if ((result = Trspi_UnloadBlob_UINT16_s(offset, NULL, blob, capacity)))
+			return result;
+		if ((result = Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC_s(offset, blob, capacity, NULL)))
+			return result;
+		if ((result = Trspi_UnloadBlob_DIGEST_s(offset, blob, capacity, NULL)))
+			return result;
+		if ((result = Trspi_UnloadBlob_UINT32_s(offset, &additionalSize, blob, capacity)))
+			return result;
+		if ((result = Trspi_UnloadBlob_s(offset, additionalSize, blob, capacity, NULL)))
+			return result;
+		if ((result = Trspi_UnloadBlob_UINT32_s(offset, &sensitiveSize, blob, capacity)))
+			return result;
+		if ((result = Trspi_UnloadBlob_s(offset, sensitiveSize, blob, capacity, NULL)))
+			return result;
+
+		return TSS_SUCCESS;
+	}
+
+	if ((result = Trspi_UnloadBlob_UINT16_s(offset, &owner->tag, blob, capacity)))
+		goto error0;
+	if ((result = Trspi_UnloadBlob_TPM_DELEGATE_PUBLIC_s(offset, blob, capacity, &owner->pub)))
+		goto error0;
+	if ((result = Trspi_UnloadBlob_DIGEST_s(offset, blob, capacity, &owner->integrityDigest)))
+		goto error1;
+	if ((result = Trspi_UnloadBlob_UINT32_s(offset, &owner->additionalSize, blob, capacity)))
+		goto error1;
+
+	if (*offset + owner->additionalSize > capacity) {
+		result = TSPERR(TSS_E_BAD_PARAMETER);
+		goto error1;
+	}
+
+	if (owner->additionalSize > 0) {
+		owner->additionalArea = malloc(owner->additionalSize);
+		if (owner->additionalArea == NULL) {
+			LogError("malloc of %u bytes failed.", owner->additionalSize);
+			result = TSPERR(TSS_E_OUTOFMEMORY);
+			goto error2;
+		}
+
+		if ((result = Trspi_UnloadBlob_s(offset, owner->additionalSize, blob, capacity, owner->additionalArea)))
+			goto error2;
+	} else {
+		owner->additionalArea = NULL;
+	}
+
+	if ((result = Trspi_UnloadBlob_UINT32_s(offset, &owner->sensitiveSize, blob, capacity)))
+		goto error2;
+
+	if (*offset + owner->sensitiveSize > capacity) {
+		result = TSPERR(TSS_E_BAD_PARAMETER);
+		goto error2;
+	}
+
+	if (owner->sensitiveSize > 0) {
+		owner->sensitiveArea = malloc(owner->sensitiveSize);
+		if (owner->sensitiveArea == NULL) {
+			LogError("malloc of %u bytes failed.", owner->sensitiveSize);
+			result = TSPERR(TSS_E_OUTOFMEMORY);
+			goto error3;
+		}
+
+		if ((result = Trspi_UnloadBlob_s(offset, owner->sensitiveSize, blob, capacity, owner->sensitiveArea)))
+			goto error3;
+	} else {
+		owner->sensitiveArea = NULL;
+	}
+
+	return TSS_SUCCESS;
+
+error3:
+	free(owner->sensitiveArea);
+	owner->sensitiveArea = NULL;
+	owner->sensitiveSize = 0;
+
+error2:
+	free(owner->additionalArea);
+	owner->additionalArea = NULL;
+	owner->additionalSize = 0;
+
+error1:
+	free(owner->pub.pcrInfo.pcrSelection.pcrSelect);
+	owner->pub.pcrInfo.pcrSelection.pcrSelect = NULL;
+	owner->pub.pcrInfo.pcrSelection.sizeOfSelect = 0;
+
+error0:
+	return result;
+}
+
 void
 Trspi_LoadBlob_TPM_DELEGATE_OWNER_BLOB(UINT64 *offset, BYTE *blob, TPM_DELEGATE_OWNER_BLOB *owner)
 {