Skip to content

Commit

Permalink
public_key: Use maps instead of records for policy tree nodes
Browse files Browse the repository at this point in the history
We do this at it will be part of the API
  • Loading branch information
IngelaAndin committed Aug 23, 2023
1 parent ac9e0d5 commit a51f3c6
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 65 deletions.
8 changes: 0 additions & 8 deletions lib/public_key/include/public_key.hrl
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,6 @@
user_state
}).

-record(policy_tree_node,
{
valid_policy,
qualifier_set,
criticality_indicator,
expected_policy_set
}).

-record(revoke_state,
{
reasons_mask,
Expand Down
133 changes: 77 additions & 56 deletions lib/public_key/src/pubkey_cert.erl
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,10 @@
%%--------------------------------------------------------------------
init_validation_state(#'OTPCertificate'{} = OtpCert, DefaultPathLen,
Options) ->
PolicyTree = [[[#policy_tree_node{valid_policy = ?anyPolicy,
qualifier_set = [],
criticality_indicator = false,
expected_policy_set = [?anyPolicy]}]]],
PolicyTree = [[[#{valid_policy => ?anyPolicy,
qualifier_set => [],
criticality_indicator => false,
expected_policy_set => [?anyPolicy]}]]],
MaxLen = proplists:get_value(max_path_length, Options, DefaultPathLen),
UserPolicySet = policy_set(Options, [?anyPolicy]),
ExplicitPolicy = policy_indicator(MaxLen,
Expand Down Expand Up @@ -941,18 +941,31 @@ policy_children(Parents, Critical, Policy, Qualifiers) ->

%% Step 2
handle_any_policy_ext(Critical, Qualifiers, Parents, Children) ->
handle_any_policy_ext(Critical, Qualifiers, Parents, Children, []).
SamLen = maybe_add_empty_children(Parents, Children),
NewChildren = handle_any_policy_ext(Critical, Qualifiers, Parents, SamLen, []),
merge_children(Children, NewChildren, []).

handle_any_policy_ext(_, _, [], Children0, AccChildren) ->
merge_children(Children0, lists:reverse(AccChildren), []);
handle_any_policy_ext(_, _, [], [], AccChildren) ->
AccChildren;
handle_any_policy_ext(Critical, Qualifiers,
[#policy_tree_node{expected_policy_set = ExpPolicySet} | ParentsRest],
Children0, Acc) ->
[#{expected_policy_set := ExpPolicySet,
valid_policy:= ValidPolicy} | ParentsRest],
[Children | RestChildren], AccChildren) ->
Nodes = [policy_node(Critical, Policy, Qualifiers,
[Policy])
[ValidPolicy])
|| Policy <- ExpPolicySet,
not lists:keymember(Policy, #policy_tree_node.valid_policy, Children0 ++ Acc)],
handle_any_policy_ext(Critical, Qualifiers, ParentsRest, Children0, [Nodes | Acc]).
not has_policy_node(Policy, Children)],
handle_any_policy_ext(Critical, Qualifiers, ParentsRest, RestChildren, [Nodes | AccChildren]).

maybe_add_empty_children(Parents, Children) ->
maybe_add_empty_children(Parents, Children, []).

maybe_add_empty_children([], _, AccChildren) ->
lists:reverse(AccChildren);
maybe_add_empty_children([_ | RestParents], [Children | RestChildren], AccChildren) ->
maybe_add_empty_children(RestParents, RestChildren, [Children | AccChildren]);
maybe_add_empty_children([_ | RestParents], [] = RestChildren, AccChildren) ->
maybe_add_empty_children(RestParents, RestChildren, [[] | AccChildren]).


%% Step 1 i:
Expand All @@ -966,7 +979,7 @@ handle_policy(_,_, _, [], _, [_|_] = Acc) ->
handle_policy(Critical, Policy, Qualifiers, [[] | Rest], Parents, Acc) ->
handle_policy(Critical, Policy, Qualifiers, Rest, Parents, Acc);
handle_policy(Critical, Policy, Qualifiers,
[#policy_tree_node{expected_policy_set = ExpPolicySet}| Rest], Parents, Acc) ->
[#{expected_policy_set := ExpPolicySet}| Rest], Parents, Acc) ->
case lists:member(Policy, ExpPolicySet) orelse ExpPolicySet == [?anyPolicy] of
true ->
Node = policy_node(Critical, Policy, [], [Policy]),
Expand All @@ -981,7 +994,7 @@ handle_prev_any_policy(_, _, _, [], []) ->
handle_prev_any_policy(_, _, _, [], Acc) ->
lists:reverse(Acc);
handle_prev_any_policy(Critical, Policy, Qualifiers,
[#policy_tree_node{valid_policy = ?'anyPolicy'}| Rest], Acc) ->
[#{valid_policy := ?'anyPolicy'}| Rest], Acc) ->
Node = policy_node(Critical, Policy, Qualifiers, [Policy]),
handle_prev_any_policy(Critical, Policy, Qualifiers, Rest, [Node| Acc]);
handle_prev_any_policy(Critical, Policy, Qualifiers, [_ |Rest], Acc) ->
Expand All @@ -1006,10 +1019,10 @@ merge_children([C1| Rest1], [C2| Rest2], Acc) ->
merge_children(Rest1, Rest2, [ C1 ++ C2 | Acc]).

policy_node(Critical, ValidPolicy, QualifierSet, ExpPolicySet) ->
#policy_tree_node{valid_policy = ValidPolicy,
criticality_indicator = Critical,
qualifier_set = QualifierSet,
expected_policy_set = ExpPolicySet}.
#{valid_policy => ValidPolicy,
criticality_indicator => Critical,
qualifier_set => QualifierSet,
expected_policy_set => ExpPolicySet}.

format_qualifers(asn1_NOVALUE) ->
[];
Expand Down Expand Up @@ -1087,9 +1100,9 @@ do_handle_policy_mapping(#'PolicyMappings_SEQOF'{
InvalidNodes = policies_nodes(IssuerPolicy, Nodes0),
prune_invalid_nodes(InvalidNodes, Tree0);
do_handle_policy_mapping(#'PolicyMappings_SEQOF'{
issuerDomainPolicy = IssuerPolicy,
subjectDomainPolicy = SubjectPolicy},
[Nodes0 | Tree], N, AnyQualifiers) when N > 0 -> %% 6.1.4. b 1:
issuerDomainPolicy = IssuerPolicy,
subjectDomainPolicy = SubjectPolicy},
[Nodes0 | Tree], N, AnyQualifiers) when N > 0 -> %% 6.1.4. b 1:
%% (1) If the policy_mapping variable is greater than 0, for each
%% node in the valid_policy_tree of depth i where ID-P is the
%% valid_policy, set expected_policy_set to the set of
Expand Down Expand Up @@ -1121,7 +1134,7 @@ do_handle_policy_mapping(#'PolicyMappings_SEQOF'{
[Nodes | Tree].

map_policies(IPolicy, SPolicy, Nodes0) ->
case is_policy_present(IPolicy, #policy_tree_node.valid_policy, Nodes0) of
case is_policy_present(IPolicy, Nodes0) of
true ->
lists:map(fun(Nodes) ->
map_policy(IPolicy, SPolicy, Nodes) end,
Expand All @@ -1130,35 +1143,35 @@ map_policies(IPolicy, SPolicy, Nodes0) ->
[]
end.

is_policy_present(_, []) ->
false;
is_policy_present(IPolicy, [Nodes | Rest]) ->
case has_policy_node(IPolicy, Nodes) of
true ->
true;
false ->
is_policy_present(IPolicy, Rest)
end.

map_policy(IPolicy, SPolicy, Nodes) ->
lists:map(
fun(#policy_tree_node{valid_policy = ValidPolicy, expected_policy_set = Set} = Node)
fun(#{valid_policy := ValidPolicy, expected_policy_set := Set} = Node)
when ValidPolicy == IPolicy ->
case Set == [ValidPolicy] of
true ->
Node#policy_tree_node{expected_policy_set = [SPolicy]};
Node#{expected_policy_set => [SPolicy]};
false ->
Node#policy_tree_node{expected_policy_set = Set ++ [SPolicy]}
Node#{expected_policy_set => Set ++ [SPolicy]}
end;
(Node) ->
Node
end, Nodes).

is_policy_present(_, _, []) ->
false;
is_policy_present(IPolicy, KeyPos, [Nodes | Rest]) ->
case lists:keymember(IPolicy, KeyPos, Nodes) of
true ->
true;
false ->
is_policy_present(IPolicy, KeyPos, Rest)
end.

map_any_policy(IPolicy, SPolicy, AnyQualifiers, Nodes) ->
case lists:keyfind(?anyPolicy, #policy_tree_node.valid_policy, Nodes) of
#policy_tree_node{criticality_indicator = Critical} ->
case pick_policy_node(?anyPolicy, Nodes) of
#{criticality_indicator := Critical} ->
[policy_node(Critical, IPolicy, AnyQualifiers, [SPolicy]) | Nodes];
false ->
no_node ->
Nodes
end.

Expand Down Expand Up @@ -1266,7 +1279,7 @@ valid_policy_node_set(RevTree, Acc) ->
valid_policy_nodes([], [], Acc) ->
Acc;
valid_policy_nodes([Parents | PRest] , [Children | CRest], Acc)->
case lists:keyfind(?anyPolicy, #policy_tree_node.valid_policy, Parents) of
case has_policy_node(?anyPolicy, Parents) of
false ->
valid_policy_nodes(PRest, CRest, Acc);
_ ->
Expand Down Expand Up @@ -1326,10 +1339,10 @@ apply_user_constraints(ValidPolicyNodeSet, UserPolicySet) ->

apply_user_constraints([], _, Acc) ->
Acc;
apply_user_constraints([#policy_tree_node{valid_policy = ?anyPolicy} | Rest],
apply_user_constraints([#{valid_policy := ?anyPolicy} | Rest],
UserPolicySet, Acc) ->
apply_user_constraints(Rest, UserPolicySet, Acc);
apply_user_constraints([#policy_tree_node{valid_policy = Policy} = Node | Rest],
apply_user_constraints([#{valid_policy := Policy} = Node | Rest],
UserPolicySet, Acc) ->
case lists:member(Policy, UserPolicySet) of
true ->
Expand All @@ -1346,38 +1359,46 @@ handle_any_policy_leafs([Leafs0 | Rest] = Tree, UserPolicySet) ->
case any_policy_child(Leafs0, 1) of
no_node ->
Tree;
{Child, N} ->
Qualifiers = Child#policy_tree_node.qualifier_set,
{#{qualifier_set := Qualifiers}, N} ->
Children =
[policy_node(false, Policy, Qualifiers, [Policy]) || Policy <- UserPolicySet],
Leafs = replace_any_policy(Leafs0, Child, N, 1, Children, []),
Leafs = replace_any_policy(Leafs0, N, 1, Children, []),
[Leafs | Rest]
end.

any_policy_child([], _) ->
no_node;
any_policy_child([Child | Rest], N) ->
case lists:keyfind(?anyPolicy, #policy_tree_node.valid_policy, Child) of
false ->
case pick_policy_node(?anyPolicy, Child) of
no_node ->
any_policy_child(Rest, N+1);
Node ->
{Node, N}
end.

replace_any_policy([Children0 | Rest], Child, N, N, NewChildren, Acc) ->
Children = replace_any_policy(Child, NewChildren, Children0, []),
lists:reverse([Children| Acc] ++ Rest);
replace_any_policy([Children0 | Rest], Child, N, M, NewChildren, Acc) ->
replace_any_policy(Rest, Child, N, M+1, NewChildren, [Children0|Acc]).
replace_any_policy([_AnyChild| Rest], N, N, NewChildren, Acc) ->
lists:reverse([NewChildren | Acc]) ++ Rest;
replace_any_policy([Children | Rest], N, M, NewChildren, Acc) ->
replace_any_policy(Rest, N, M+1, NewChildren, [Children|Acc]).

replace_any_policy(Child, NewChildren, [Child | Rest], Acc) ->
lists:reverse([[NewChildren | Rest] | Acc]);
replace_any_policy(Child, NewChildren, [Other| Rest], Acc) ->
replace_any_policy(Child, NewChildren, Rest, [Other | Acc]).

%% End Wrap Up Policy Handling -------------------------------------------------

%% Start Policy Tree Primitives -----------------------------------------------
has_policy_node(_, []) ->
false;
has_policy_node(Policy, [#{valid_policy := Policy} |_]) ->
true;
has_policy_node(Policy, [_ | Rest]) ->
has_policy_node(Policy, Rest).

pick_policy_node(_, []) ->
no_node;
pick_policy_node(Policy, [#{valid_policy := Policy} = Node |_]) ->
Node;
pick_policy_node(Policy, [_ | Rest]) ->
pick_policy_node(Policy, Rest).

prune_tree([_]) ->
?EMPTY_POLICY_TREE;
prune_tree([_,_] = Tree) ->
Expand Down Expand Up @@ -1415,7 +1436,7 @@ policies_nodes(Policy, Nodes) ->

policies_nodes(_, [], Acc) ->
lists:reverse(Acc);
policies_nodes(Policy, [#policy_tree_node{valid_policy = Policy} = Node | Nodes], Acc) ->
policies_nodes(Policy, [#{valid_policy := Policy} = Node | Nodes], Acc) ->
policies_nodes(Policy, Nodes, [Node | Acc]);
policies_nodes(Policy, [_N| Nodes], Acc) ->
policies_nodes(Policy, Nodes, Acc).
Expand Down
7 changes: 6 additions & 1 deletion lib/public_key/src/public_key.erl
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,11 @@
#{server_config := [conf_opt()], client_config := [conf_opt()]}.
-type test_root_cert() ::
#{cert := der_encoded(), key := public_key:private_key()}.
-type policy_node() ::
#{valid_policy := oid(),
criticality_indicator := boolean(),
qualifier_set => [#'PolicyInformation'{}],
expected_policy_set => [oid()]}.

-define(UINT32(X), X:32/unsigned-big-integer).
-define(DER_NULL, <<5, 0>>).
Expand Down Expand Up @@ -1141,7 +1146,7 @@ pkix_normalize_name(Issuer) ->
CertChain :: [cert() | combined_cert()],
Options :: [{max_path_length, integer()} | {verify_fun, {fun(), term()}}],
PublicKeyInfo :: public_key_info(),
PolicyTree :: list().
PolicyTree :: [[policy_node()]].

%% Description: Performs a basic path validation according to RFC 5280.
%%--------------------------------------------------------------------
Expand Down

0 comments on commit a51f3c6

Please sign in to comment.