krabka_verified/delegation_token/
token_mutation_decision.rs1use {
2 super::{
3 ScramCredentialSource, TokenApi, TokenApiAdmission, TokenMutationDecision,
4 TokenMutationFacts, TokenMutationKind, TokenMutationState,
5 },
6 creusot_std::prelude::*,
7};
8
9#[ensures((result == ScramCredentialSource::Regular) == has_regular_credential)]
22#[ensures((result == ScramCredentialSource::DelegationToken) ==
23 (!has_regular_credential && token_mechanism && has_token))]
24#[ensures((result == ScramCredentialSource::Unknown) ==
25 (!has_regular_credential && (!token_mechanism || !has_token)))]
26#[must_use]
27pub fn scram_credential_source(
28 has_regular_credential: bool,
29 token_mechanism: bool,
30 has_token: bool,
31) -> ScramCredentialSource {
32 if has_regular_credential {
33 ScramCredentialSource::Regular
34 } else if token_mechanism && has_token {
35 ScramCredentialSource::DelegationToken
36 } else {
37 ScramCredentialSource::Unknown
38 }
39}
40
41#[ensures(result == (owner_filter_matches
55 && (caller_is_owner || caller_is_requester || caller_is_renewer || acl_allows)))]
56#[allow(
57 clippy::fn_params_excessive_bools,
58 reason = "the proof classifies independent token visibility relationships"
59)]
60#[must_use]
61pub fn token_describe_visible(
62 owner_filter_matches: bool,
63 caller_is_owner: bool,
64 caller_is_requester: bool,
65 caller_is_renewer: bool,
66 acl_allows: bool,
67) -> bool {
68 owner_filter_matches
69 && (caller_is_owner || caller_is_requester || caller_is_renewer || acl_allows)
70}
71
72#[ensures((result == TokenApiAdmission::Allow) == (
83 has_authenticated_identity && !authenticated_via_token
84))]
85#[ensures((result == TokenApiAdmission::Reject) == (
86 !has_authenticated_identity || authenticated_via_token
87))]
88#[must_use]
89pub fn token_api_admission(
90 has_authenticated_identity: bool,
91 authenticated_via_token: bool,
92 _api: TokenApi,
93) -> TokenApiAdmission {
94 if has_authenticated_identity && !authenticated_via_token {
95 TokenApiAdmission::Allow
96 } else {
97 TokenApiAdmission::Reject
98 }
99}
100
101#[cfg(creusot)]
103#[cfg_attr(test, mutants::skip)]
104#[logic(open)]
105fn token_generation_live(facts: TokenMutationFacts) -> bool {
106 pearlite! { facts.now_ms@ >= 0
107 && facts.expected_expiry_ms@ >= facts.now_ms@
108 && facts.max_timestamp_ms@ >= facts.now_ms@
109 && facts.expected_expiry_ms@ <= facts.max_timestamp_ms@ }
110}
111
112#[ensures((result == TokenMutationDecision::Append) == (
121 !facts.uncommitted_tail
122 && facts.state == TokenMutationState::Expected
123 && match facts.kind {
124 TokenMutationKind::Delete => true,
125 TokenMutationKind::Renew =>
126 token_generation_live(facts)
127 && facts.incoming_expiry_ms@ != facts.expected_expiry_ms@
128 && facts.incoming_expiry_ms@ >= facts.now_ms@
129 && facts.incoming_expiry_ms@ <= facts.max_timestamp_ms@,
130 TokenMutationKind::Expire =>
131 token_generation_live(facts)
132 && facts.incoming_expiry_ms@ >= 0
133 && facts.incoming_expiry_ms@ <= facts.max_timestamp_ms@,
134 }))]
135#[ensures((result == TokenMutationDecision::Retry) == (
136 !facts.uncommitted_tail
137 && (facts.state == TokenMutationState::Applied
138 || (facts.kind == TokenMutationKind::Delete
139 && facts.state == TokenMutationState::Missing)
140 || (facts.kind == TokenMutationKind::Renew
141 && facts.state == TokenMutationState::Expected
142 && facts.incoming_expiry_ms@ == facts.expected_expiry_ms@
143 && token_generation_live(facts)))))]
144#[must_use]
145pub fn token_mutation_decision(facts: TokenMutationFacts) -> TokenMutationDecision {
146 if facts.uncommitted_tail {
147 return TokenMutationDecision::Reject;
148 }
149 match facts.state {
150 TokenMutationState::Applied => return TokenMutationDecision::Retry,
151 TokenMutationState::Missing => {
152 return match facts.kind {
153 TokenMutationKind::Delete => TokenMutationDecision::Retry,
154 TokenMutationKind::Renew | TokenMutationKind::Expire => {
155 TokenMutationDecision::Reject
156 }
157 };
158 }
159 TokenMutationState::Stale => return TokenMutationDecision::Reject,
160 TokenMutationState::Expected => {}
161 }
162
163 match facts.kind {
164 TokenMutationKind::Delete => TokenMutationDecision::Append,
165 TokenMutationKind::Renew => {
166 if facts.now_ms < 0
167 || facts.expected_expiry_ms < facts.now_ms
168 || facts.max_timestamp_ms < facts.now_ms
169 || facts.expected_expiry_ms > facts.max_timestamp_ms
170 {
171 return TokenMutationDecision::Reject;
172 }
173 if facts.incoming_expiry_ms == facts.expected_expiry_ms {
174 TokenMutationDecision::Retry
175 } else if facts.incoming_expiry_ms >= facts.now_ms
176 && facts.incoming_expiry_ms <= facts.max_timestamp_ms
177 {
178 TokenMutationDecision::Append
179 } else {
180 TokenMutationDecision::Reject
181 }
182 }
183 TokenMutationKind::Expire => {
184 if facts.now_ms >= 0
185 && facts.expected_expiry_ms >= facts.now_ms
186 && facts.max_timestamp_ms >= facts.now_ms
187 && facts.expected_expiry_ms <= facts.max_timestamp_ms
188 && facts.incoming_expiry_ms >= 0
189 && facts.incoming_expiry_ms <= facts.max_timestamp_ms
190 {
191 TokenMutationDecision::Append
192 } else {
193 TokenMutationDecision::Reject
194 }
195 }
196 }
197}