/// <summary> /// A "normalized" policy is one transformed into disjunctive normal form, /// in which a collection of policy "AND chains" is combined with PolicyOR /// before submission to the TPM. /// Callers must provide an-array-of-arrays of TpmPolicyACEs. The arrays may NOT /// contain PolicyOr (these will be added automatically), but each array MUST be /// terminated with a unique string identifier encoded in a TpmPolicyChainId. /// </summary> /// <param name="policy"></param> public void CreateNormalizedPolicy(PolicyAce[][] policy) { // To validate that the input does not have any repeated branchIds or ACEs var branchIdDict = new Dictionary <string, string>(); var aces = new HashSet <object>(); int numBranches = 0; bool unnamedBranches = false; // The following code validates and transforms the array-of-arrays into a linked // list + OR nodes tree. First collect lists of chains in the chains collection. var chains = new List <PolicyAce>(); foreach (PolicyAce[] chain in policy) { numBranches++; PolicyAce leaf = null; PolicyAce previousAce = null; PolicyAce root = null; // Turn the array into a doubly-linked list foreach (PolicyAce ace in chain) { // Repeats are illegal if (aces.Contains(ace)) { Globs.Throw <ArgumentException>("CreateNormalizedPolicy: " + "Repeated ACE in policy"); } // Already associated with a session is illegal if (ace.AssociatedPolicy != null) { Globs.Throw <ArgumentException>("CreateNormalizedPolicy: " + "ACE is already associated with a policy"); } ace.AssociatedPolicy = this; aces.Add(ace); // OR is illegal in normal form (these are added automatically // at the root to union the arrays that are input to this function). if (ace is TpmPolicyOr) { Globs.Throw <ArgumentException>("CreateNormalizedPolicy: " + "Normalized form cannot contain TpmPolicyOr"); } if (previousAce != null) { previousAce.NextAce = ace; } ace.PreviousAce = previousAce; previousAce = ace; // Is the branchId valid? string branchId = ace.BranchID; if (!String.IsNullOrEmpty(branchId)) { if (branchIdDict.ContainsKey(branchId)) { Globs.Throw <ArgumentException>("CreateNormalizedPolicy: " + "Repeated branch-identifier " + branchId); } branchIdDict.Add(branchId, ""); } if (root == null) { root = ace; } leaf = ace; } // Does the leaf have a branch ID? if (leaf != null && String.IsNullOrEmpty(leaf.BranchID)) { unnamedBranches = true; } // Else we have a good chain starting at root chains.Add(root); } if (unnamedBranches && numBranches != 1) { throw new ArgumentException("Policy-chain leaf does not have a branch identifier"); } // We now have a list of chains in chains. int numChains = chains.Count; // A single chain (no ORs) if (numChains == 1) { PolicyRoot = chains[0]; return; } // Each TPM_or can take up to 8 inputs. We will add OR-aces to the root // to capture all chains. The algorithm is that we create an OR and keep // adding chains in the input order until full (if it is the last chain) // or one-less than full. Then create a new OR, attach it to the last OR // and keep filling as before. var theRoot = new TpmPolicyOr(); TpmPolicyOr currentOrAce = theRoot; for (int j = 0; j < numChains; j++) { bool lastChain = (j == numChains - 1); if ((currentOrAce.PolicyBranches.Count < 7) || lastChain) { currentOrAce.AddPolicyBranch(chains[j]); } else { // We have overflowed the TpmPolicyOr so add a new child-OR // attached to the previous as the final (8th) branch. var nextOr = new TpmPolicyOr(); currentOrAce.AddPolicyBranch(nextOr); currentOrAce = nextOr; currentOrAce.AddPolicyBranch(chains[j]); } } // All input chains are connected up to one or more ORs at the root so we are done. PolicyRoot = theRoot; }
/// <summary> /// A "normalized" policy is one transformed into disjunctive normal form in which a collection /// of policy "AND chains" is combined with PolicyOR before submission to the TPM. /// Callers must provide an-array-of-arrays of TpmPolicyACEs. The arrays may NOT /// contain PolicyOr (these will be added automatically), but each array MUST be terminated /// with a unique string identifier encoded in a TpmPolicyChainId. /// </summary> /// <param name="policy"></param> public void CreateNormalizedPolicy(PolicyAce[][] policy) { // To validate that the input does not have any repeated branchIds or ACEs var branchIdDict = new Dictionary<string, string>(); var aces = new HashSet<object>(); int numBranches = 0; bool unnamedBranches = false; // The following code validates and transforms the array-of-arrays into a linked // list + OR nodes tree. First collect lists of chains in the chains collection. var chains = new List<PolicyAce>(); foreach (PolicyAce[] chain in policy) { numBranches++; PolicyAce leaf = null; PolicyAce previousAce = null; PolicyAce root = null; // Turn the array into a doubly-linked list foreach (PolicyAce ace in chain) { // Repeats are illegal if (aces.Contains(ace)) { Globs.Throw<ArgumentException>("CreateNormalizedPolicy: Repeated ACE in policy"); } // Already associated with a session is illegal if (ace.AssociatedPolicy != null) { Globs.Throw<ArgumentException>("CreateNormalizedPolicy: ACE is already associated with a policy"); } ace.AssociatedPolicy = this; aces.Add(ace); // OR is illegal in normal form (these are added automatically // at the root to union the arrays that are input to this function). if (ace is TpmPolicyOr) { Globs.Throw<ArgumentException>("CreateNormalizedPolicy: Normalized form cannot contain TpmPolicyOr"); } if (previousAce != null) { previousAce.NextAce = ace; } ace.PreviousAce = previousAce; previousAce = ace; // Is the branchId valid? string branchId = ace.BranchIdentifier; if (!String.IsNullOrEmpty(branchId)) { if (branchIdDict.ContainsKey(branchId)) { Globs.Throw<ArgumentException>("CreateNormalizedPolicy: Repeated branch-identifier " + branchId); } branchIdDict.Add(branchId, ""); } if (root == null) { root = ace; } leaf = ace; } // Does the leaf have a branch ID? if (leaf != null && String.IsNullOrEmpty(leaf.BranchIdentifier)) { unnamedBranches = true; } // Else we have a good chain starting at root chains.Add(root); } if (unnamedBranches && numBranches != 1) { throw new ArgumentException("Policy-chain leaf does not have a branch identifier"); } // We now have a list of chains in chains. int numChains = chains.Count; // A single chain (no ORs) if (numChains == 1) { PolicyRoot = chains[0]; return; } // Each TPM_or can take up to 8 inputs. We will add OR-aces to the root to capture all // chains. The algorithm is that we create an OR and keep adding chains in the input order // until full (if it is the last chain) or one-less than full. Then create a new OR, attach it // to the last OR and keep filling as before. var theRoot = new TpmPolicyOr(); TpmPolicyOr currentOrAce = theRoot; for (int j = 0; j < numChains; j++) { bool lastChain = (j == numChains - 1); if ((currentOrAce.PolicyBranches.Count < 7) || lastChain) { currentOrAce.AddPolicyBranch(chains[j]); } else { // We have overflowed the TpmPolicyOr so add a new child-OR // attached to the previous as the final (8th) branch. var nextOr = new TpmPolicyOr(); currentOrAce.AddPolicyBranch(nextOr); currentOrAce = nextOr; currentOrAce.AddPolicyBranch(chains[j]); } } // All input chains are connected up to one or more ORs at the root so we are done. PolicyRoot = theRoot; }