File: handshake_io_lowlevel.saw

package info (click to toggle)
aws-crt-python 0.24.0%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 75,932 kB
  • sloc: ansic: 418,984; python: 23,626; makefile: 6,035; sh: 4,075; ruby: 208; java: 82; perl: 73; cpp: 25; xml: 11
file content (522 lines) | stat: -rw-r--r-- 23,703 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
////////////////////////////////////////////////////////////////
// Copyright 2019 Galois, Inc. All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License").
// You may not use this file except in compliance with the License.
// A copy of the License is located at
//
//  http://aws.amazon.com/apache2.0
//
// or in the "license" file accompanying this file. This file is distributed
// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
// express or implied. See the License for the specific language governing
// permissions and limitations under the License.
//
////////////////////////////////////////////////////////////////
//
// This file describes the correspondence between the Cryptol
// specification of the TLS handshake and the C code in
// tls/s2n_handshake_io.c, allowing SAW to prove that the code
// corresponds to the specification.
//
////////////////////////////////////////////////////////////////


enable_experimental;
// lax_loads_and_stores is needed to support the uses of
// llvm_points_to_bitfield in the specifications below. As a result, SAW will
// return fresh, symbolic values when it reads from uninitialized memory. Make
// sure all of the arguments are initialized in the preconditions of a
// specification, or else SAW will fill them in with underconstrained symbolic
// values!
enable_lax_loads_and_stores;

// Low level specifications for some of the functions and constants declared in
// tls/s2n_handshake_io.c
import "s2n_handshake_io.cry";

llvm <- llvm_load_module "../../bitcode/all_llvm.bc";
print "Loaded bitcode via Crucible";

////////////////////////////////////////////////////////////////
// References to various components of the connection state:
// The Cryptol definitions are located in the s2n_handshake_io.cry file.
// Those Cryptol definitions will be compared against the actual C
// definitions by this SAW script.
////////////////////////////////////////////////////////////////

//conn->mode
let conn_mode pconn = crucible_field pconn "mode";

let secure_crypto_params pconn = crucible_field pconn "secure";

//conn->secure->cipher_suite->key_exchange_alg->flags
let conn_secure_cipher_suite crypto_params = crucible_field crypto_params "cipher_suite";

//let key_exchange_algorithm csuite = crucible_elem csuite 3;
let key_exchange_algorithm csuite = crucible_field csuite "key_exchange_alg";

let kea_is_ephemeral kea = crucible_elem kea 0;
//let kea_is_ephemeral kea = crucible_field kea "is_ephemeral";

//conn->status_type
let conn_status_type pconn = crucible_field pconn "status_type";

//conn->config
let conn_config pconn = crucible_field pconn "config";

//conn->config -> client_cert_auth_type
let config_cca_type config = (crucible_field config "client_cert_auth_type");

//conn->handshake_params.our_chain_and_key->ocsp_status.size
let ocsp_status_size cert_and_key =
    crucible_field (crucible_field (cert_and_key) "ocsp_status") "size";

let {{
// Convert a Bit to a length-1 bitvector.
bit_to_bv1 : Bit -> [1]
bit_to_bv1 b = [b]

// Convert a length-1 bitvector to a Bit.
bv1_to_bit : [1] -> Bit
bv1_to_bit bv1 = bv1 @ 0
}};

//conn->session_ticket_status
let conn_session_ticket_status pconn = (crucible_field pconn "session_ticket_status");

//conn->client_cert_auth_type
let cca_type pconn = crucible_field pconn "client_cert_auth_type";

//conn->client_cert_auth_type_overridden
let cca_type_ov pconn = crucible_field pconn "client_cert_auth_type_overridden";

//conn->handshake.handshake_type
let conn_handshake_handshake_type pconn =
    crucible_field (crucible_field pconn "handshake") "handshake_type";

//conn->handshake.message_number
let conn_handshake_message_number pconn =
    crucible_field (crucible_field pconn "handshake") "message_number";

//conn->handshake.state_machine
let conn_handshake_state_machine pconn =
    crucible_field (crucible_field pconn "handshake") "state_machine";

//conn->handshake_params.our_chain_and_key
let conn_chain_and_key pconn =
    crucible_field (crucible_field pconn "handshake_params") "our_chain_and_key";

//conn->psk_params.chosen_psk
let conn_chosen_psk pconn =
    crucible_field (crucible_field pconn "psk_params") "chosen_psk";

//conn->early_data_state
let conn_early_data_state pconn = crucible_field pconn "early_data_state";

// Ghost state that represents the number of times the connection write socket
// has been corked/uncorked. 
corked <- crucible_declare_ghost_state "corked";
crucible_ghost_value corked {{ 0 : [2] }};

// setup_handshake_common de-serializes parts of the s2n_handshake and
// s2n_connection structs into a Cryptol record. It also deserializes the ghost
// state. We use the suffix "_common" since it captures the properties shared
// in common between setup_connection and setup_psk_connection.
//
// The chosen_psk_null argument is true if conn->psk_params.chosen_psk should
// be set to NULL, which enables the use of FULL_HANDSHAKE if TLS 1.3 is used.
// If false, then chosen_psk is set to a non-NULL value, disabling
// FULL_HANDSHAKE if TLS 1.3 is used. The value of conn->psk_params.chosen_psk
// has no effect if TLS 1.2 is used.
let setup_connection_common chosen_psk_null = do {
   pconn <- crucible_alloc (llvm_struct "struct.s2n_connection");
   
   version <- crucible_fresh_var "version" (llvm_int 8);
   crucible_precond {{ version != S2N_UNKNOWN_PROTOCOL_VERSION /\ version <= S2N_TLS13 }};
   crucible_points_to (crucible_field pconn "actual_protocol_version") (crucible_term version);
   
   mode <- crucible_fresh_var "mode" (llvm_int 32);
   crucible_points_to (conn_mode pconn) (crucible_term mode);
   
   handshake_type <- crucible_fresh_var "handshake_type" (llvm_int 32);
   crucible_points_to (conn_handshake_handshake_type pconn)
                      (crucible_term handshake_type); 

   message_number <- crucible_fresh_var "message_number" (llvm_int 32);
   crucible_points_to (conn_handshake_message_number pconn)
                      (crucible_term message_number);

   state_machine <- crucible_fresh_var "state_machine" (llvm_int 32);
   crucible_points_to (conn_handshake_state_machine pconn)
   (crucible_term state_machine);

   cork_val <- crucible_fresh_var "corked" (llvm_int 2);
   crucible_ghost_value corked cork_val;

   // We assume that the client_cert_auth_type_overridden flag in s2n_connection is set.
   // If that flag is not set, auth_type / "cca_type" could be determined by the config
   // or just set to a default value. Since we're primarily interested in the handshake
   // here and the end result is the same, just consider the connection auth_type.
   cca_ov <- crucible_fresh_var "cca_ov" (llvm_int 8);
   crucible_points_to (cca_type_ov pconn) (crucible_term cca_ov);
   crucible_equal (crucible_term cca_ov) (crucible_term {{1 : [8]}});

   cca <- crucible_fresh_var "cca" (llvm_int 32);
   crucible_points_to (cca_type pconn) (crucible_term cca);

   secure <- crucible_alloc (llvm_struct "struct.s2n_crypto_parameters");
   crucible_points_to (secure_crypto_params pconn) secure;

   cipher_suite <- crucible_alloc (llvm_struct "struct.s2n_cipher_suite");
   crucible_points_to (conn_secure_cipher_suite secure) cipher_suite;

   kea <- crucible_alloc (llvm_struct "struct.s2n_kex");
   crucible_points_to (key_exchange_algorithm cipher_suite) kea;

   eph_flag <- crucible_fresh_var "eph_flag" (llvm_int 8);
   crucible_points_to (kea_is_ephemeral kea) (crucible_term eph_flag);

   config <- crucible_alloc (llvm_struct "struct.s2n_config");
   crucible_points_to (conn_config pconn) config;

   cak <- crucible_alloc (llvm_struct "struct.s2n_cert_chain_and_key");
   crucible_points_to (conn_chain_and_key pconn) cak;

   status_size <- crucible_fresh_var "status_size" (llvm_int 32);
   crucible_points_to (ocsp_status_size cak) (crucible_term status_size);
   crucible_equal (crucible_term status_size) (crucible_term {{zero : [32]}});

   // We assume that corking/uncorking is managed by s2n, so set the corked_io
   // bit in s2n_connection to one...
   let corked_io = {{ True }};
   llvm_points_to_bitfield pconn "corked_io" (llvm_term {{ bit_to_bv1 corked_io }});

   // ...we assume that the client_session_resumed bit in s2n_connection must
   // be zero...
   llvm_points_to_bitfield pconn "client_session_resumed" (llvm_term {{ 0 : [1] }});

   // ...we currently require that the use_tickets bit in s2n_config must be
   // zero...
   llvm_points_to_bitfield config "use_tickets" (llvm_term {{ 0 : [1] }});

   // ...on the other hand, the quic_enabled bits in both s2n_connection and
   // s2n_config are allowed to be either 0 or 1. As such, we don't need to
   // impose any direct constraints on them. We simply query which values
   // they have taken on during simulation and remember them for later.
   conn_quic_enabled <- llvm_fresh_var "conn_quic_enabled" (llvm_int 1);
   llvm_points_to_bitfield pconn "quic_enabled" (llvm_term conn_quic_enabled);
   config_quic_enabled <- llvm_fresh_var "config_quic_enabled" (llvm_int 1);
   llvm_points_to_bitfield config "quic_enabled" (llvm_term config_quic_enabled);
   let quic_enabled_bit = {{ bv1_to_bit conn_quic_enabled \/ bv1_to_bit config_quic_enabled }};

   session_ticket_status <- crucible_fresh_var "session_ticket_status" (llvm_int 32);
   crucible_points_to (conn_session_ticket_status pconn) (crucible_term session_ticket_status);

   ocsp_flag <- crucible_fresh_var "ocsp_flag" (llvm_int 32);
   crucible_points_to (conn_status_type pconn) (crucible_term ocsp_flag);

   if chosen_psk_null
      then crucible_points_to (conn_chosen_psk pconn) crucible_null
      else do { chosen_psk <- crucible_alloc (llvm_struct "struct.s2n_psk");
                crucible_points_to (conn_chosen_psk pconn) chosen_psk;
              };
   let chosen_psk_null_bit = if chosen_psk_null then {{ True }} else {{ False }};

   early_data_state <- crucible_fresh_var "early_data_state" (llvm_int 32);
   crucible_points_to (conn_early_data_state pconn) (crucible_term early_data_state);

   no_client_cert <- crucible_fresh_var "no_client_cert" (llvm_int 8);

   npn_negotiated <- llvm_fresh_var "npn_negotiated" (llvm_int 1);
   llvm_points_to_bitfield pconn "npn_negotiated" (llvm_term npn_negotiated);
   let npn_negotiated_bit = {{ bv1_to_bit npn_negotiated }};

   // This returns a connection containing a handshake. If the connection or the handshake
   // definitions are changed, they must also be changed here.
   return (pconn, {{ {corked_io = corked_io
                     ,mode      = mode
                     ,handshake = {message_number = message_number
                                  ,handshake_type = handshake_type
                                  ,state_machine = state_machine }
                     ,corked    = cork_val
                     ,is_caching_enabled = False
                     ,key_exchange_eph = eph_flag != zero
                     ,server_can_send_ocsp =
                            ((ocsp_flag == 1) && (status_size > 0)) ||
                            ((mode == 1) && (ocsp_flag == 1))
                     ,resume_from_cache = False
                     ,client_auth_flag = if mode == S2N_CLIENT then cca == S2N_CERT_AUTH_REQUIRED else
                                         if mode == S2N_SERVER then cca != S2N_CERT_AUTH_NONE     else False
                     ,no_client_cert = no_client_cert != zero
                     ,actual_protocol_version = version
                     ,early_data_state = early_data_state
                     ,chosen_psk_null = chosen_psk_null_bit
                     ,quic_enabled = quic_enabled_bit
                     ,npn_negotiated = npn_negotiated_bit
                     }
                  }}); 
};

// Set conn->psk_params.chosen_psk to NULL, which enables the use of FULL_HANDSHAKE
// if TLS 1.3 is used. Note that if TLS 1.2 is used, there is no difference between
// this function and setup_psk_connection.
let setup_connection = setup_connection_common true;

// Set conn->psk_params.chosen_psk to a non-NULL value, which disables the use of FULL_HANDSHAKE
// if TLS 1.3 is used. Note that if TLS 1.2 is used, there is no difference between
// this function and setup_connection.
let setup_psk_connection = setup_connection_common false;


// This function checks that the values of the state_machine array are what we
// expect. 'state_machine' is the pointer to the beginning of the array, 'index_term' 
// is the term representing the index in the array.
let verify_state_machine_elem state_machine state_machine_model index_term = do {
    let index = eval_int index_term;
    let abstract = {{ state_machine_model @ index_term }};

    crucible_points_to (crucible_elem (crucible_elem state_machine index) 0) (crucible_term {{ abstract.record_type }});

    crucible_points_to (crucible_elem (crucible_elem state_machine index) 1) (crucible_term {{ abstract.message_type }});

    crucible_points_to (crucible_elem (crucible_elem state_machine index) 2) (crucible_term {{ abstract.writer }});

};

// For now axiomitize this is always false and see if we can prove something
let s2n_allowed_to_cache_connection_spec = do {
    pconf <- crucible_alloc_readonly (llvm_struct "struct.s2n_connection");

    crucible_execute_func [pconf];
    crucible_return (crucible_term {{ 0 : [32] }});
};

let s2n_connection_get_client_auth_type_spec = do {
    pconn <- crucible_alloc_readonly (llvm_struct "struct.s2n_connection");
    auth_type <- crucible_alloc (llvm_int 32);

    cca_ov <- crucible_fresh_var "cca_ov" (llvm_int 8);
    crucible_points_to (cca_type_ov pconn) (crucible_term cca_ov);

    config <- crucible_alloc_readonly (llvm_struct "struct.s2n_config");
    crucible_points_to (conn_config pconn) config;

    config_cca_ov <- llvm_fresh_var "config_cca_ov" (llvm_int 8);
    crucible_points_to (crucible_field config "client_cert_auth_type_overridden") (crucible_term config_cca_ov);

    config_cca <- crucible_fresh_var "config_cca" (llvm_int 32);
    crucible_points_to (config_cca_type config) (crucible_term config_cca);

    cca <- crucible_fresh_var "cca" (llvm_int 32);
    crucible_points_to (cca_type pconn) (crucible_term cca);

    mode <- crucible_fresh_var "mode" (llvm_int 32);
    crucible_points_to (conn_mode pconn) (crucible_term mode);

    crucible_execute_func [pconn, auth_type];

    crucible_points_to (auth_type) (crucible_term {{
        if cca_ov != zero then cca else
        if config_cca_ov != zero then config_cca else
        if mode == S2N_CLIENT then S2N_CERT_AUTH_OPTIONAL else
        S2N_CERT_AUTH_NONE
    }});

    crucible_return (crucible_term {{ 0 : [32] }});
};

// Specification for s2n_conn_set_handshake_type that sets up simulation of it
// by conn_set_handshake_type (low-level model function)
let s2n_conn_set_handshake_type_spec chosen_psk_null = do {
    (pconn, conn) <- setup_connection_common chosen_psk_null;
    // We assume that the connection struct denotes a valid connection state
    crucible_precond {{ valid_connection conn }};

    // symbolically execute s2n_conn_set_handshake_type
    crucible_execute_func [pconn];

    // Next we check that the changes to s2n_connection fields are
    // simulated by the low-level specification of the function. We do
    // this by running the model function conn_set_handshake_type on the
    // deserealized pre-state of the s2n_connection struct and checking
    // that values of the fields of the resulting struct match the fields
    // of the post-state of the s2n_connection struct. In this case only handshake
    // type should change
    let conn' = {{ conn_set_handshake_type conn }};
    crucible_ghost_value corked {{ conn'.corked }};
    crucible_points_to (conn_handshake_handshake_type pconn) (crucible_term {{ conn'.handshake.handshake_type }});

    // assert that s2n_conn_set_handshake_type returns 0 (true if the 4
    // functions it calls don't fail)
    crucible_return (crucible_term {{ 0 : [32] }});
};

// specification for s2n_advance_message that sets up simulation of it
// by advance_message (low-level model function)
let s2n_advance_message_spec = do {
    // Note that s2n_advance_message() doesn't actually care about the value of
    // chosen_psk, so we arbitrarily set it to NULL here by using
    // setup_connection. Using setup_psk_connection would work just as well.
    (pconn, conn) <- setup_connection;
    // We assume that the connection struct denotes a valid connection state
    crucible_precond {{ valid_connection conn }};

    // symbolically execute s2n_advance_message
    crucible_execute_func [pconn];

    // Next we check that the changes to s2n_connection fields are
    // simulated by the low-level specification of the function. We do
    // this by running the model function advance_message on the
    // deserealized pre-state of the s2n_connection struct and checking
    // that values of the fields of the resulting struct match the fields
    // of the post-state of the s2n_connection struct.
    let conn' = {{ advance_message conn }};
    crucible_ghost_value corked {{ conn'.corked }};
    llvm_points_to_bitfield pconn "corked_io" (llvm_term {{ bit_to_bv1 (conn'.corked_io) }});
    crucible_points_to (conn_mode pconn) (crucible_term {{ conn'.mode }});
    crucible_points_to (conn_handshake_handshake_type pconn) (crucible_term {{ conn'.handshake.handshake_type }});
    crucible_points_to (conn_handshake_message_number pconn) (crucible_term {{ conn'.handshake.message_number }});

    // make sure the low-level spec representation of the declarative
    // handshake/cork-uncork state machine is equivalent to the one in
    // s2n
    // The Cryptol representations are defined here: tests/saw/spec/handshake/s2n_handshake_io.cry
    //
    // Note that we use crucible_points_to_untyped here rather than
    // crucible_points_to because LLVM 7 and later represent static arrays that
    // are partially initialized with zeroes as packed structs. For more
    // information, see
    // https://llvm.discourse.group/t/array-layout-changed-by-clang-llvm-starting-from-version-7/2271
    //
    // Changing the Cryptol definitions of the state machines to match these
    // new types would be annoying, and moreover, it isn't guaranteed that
    // future versions of LLVM won't change the types further. Fortunately, the
    // in-memory representation of the arrays hasn't changed, just the types.
    // As a result, we can use crucible_points_to_untyped to check if the two
    // state machines are bitwise equivalent without checking the types.
    crucible_points_to_untyped (crucible_global "handshakes") (crucible_term {{ handshakes }});
    crucible_points_to_untyped (crucible_global "tls13_handshakes") (crucible_term {{ tls13_handshakes }});
    
    let messages = [ {{CLIENT_HELLO : [5]}}
                   , {{SERVER_HELLO : [5]}}
                   , {{SERVER_NEW_SESSION_TICKET : [5]}}
                   , {{SERVER_CERT : [5]}}
                   , {{SERVER_CERT_STATUS : [5]}}
                   , {{SERVER_KEY : [5]}}
                   , {{SERVER_CERT_REQ : [5]}}
                   , {{SERVER_HELLO_DONE : [5]}}
                   , {{CLIENT_CERT : [5]}}
                   , {{CLIENT_KEY : [5]}}
                   , {{CLIENT_CERT_VERIFY : [5]}}
                   , {{CLIENT_CHANGE_CIPHER_SPEC : [5]}}
                   , {{CLIENT_NPN : [5]}}
                   , {{CLIENT_FINISHED : [5]}}
                   , {{SERVER_CHANGE_CIPHER_SPEC : [5]}}
                   , {{SERVER_FINISHED : [5]}}
                   , {{ENCRYPTED_EXTENSIONS : [5]}}
                   , {{SERVER_CERT_VERIFY : [5]}}
                   , {{HELLO_RETRY_MSG : [5]}}
                   , {{END_OF_EARLY_DATA : [5]}}
                   , {{APPLICATION_DATA : [5]}}
                   ];

    for messages (verify_state_machine_elem (crucible_global "state_machine") {{ state_machine }} );
    for messages (verify_state_machine_elem (crucible_global "tls13_state_machine") {{ tls13_state_machine }} );

    // assert that s2n_advance_message returns 0 (true if the 4
    // functions it calls don't fail)
    crucible_return (crucible_term {{ 0 : [32] }});
};

// Specs for the 5 functions that s2n_advance_message calls. Right now
// we just assume the specs and don't verify them. That's because we
// don't model the state that they depend on, instead, making assumptions
// about it: we use managed corking and the socket was initially uncorked.

// Specification for s2n_socket_write_uncork. The relevant part is
// that it decrements the 'corked' ghost variable to indicate that the socket
// has been uncorked.
let s2n_socket_write_uncork_spec = do {
    pconn <- crucible_alloc_readonly (llvm_struct "struct.s2n_connection");
    cork_val <- crucible_fresh_var "corked" (llvm_int 2);
    crucible_ghost_value corked cork_val;

    crucible_execute_func [pconn];

    crucible_ghost_value corked {{ cork_val - 1 }};

    crucible_return (crucible_term {{ 0 : [32] }});
};

// Specification for s2n_generate_new_client_session_id. This is essentially
// a noop function that returns 0 from the perspective of our current proof
let s2n_generate_new_client_session_id_spec = do {
    pconn <- crucible_alloc_readonly (llvm_struct "struct.s2n_connection");
   
    crucible_execute_func [pconn];

    crucible_return (crucible_term {{ 0 : [32] }});
};

// Specification for s2n_resume_decrypt_session_ticket_spec. This is essentially
// a noop function that returns 0 from the perspective of our current proof
let s2n_resume_decrypt_session_ticket_spec = do {
    pconn <- crucible_alloc_readonly (llvm_struct "struct.s2n_connection");
    from <- crucible_alloc_readonly (llvm_struct "struct.s2n_stuffer");

    crucible_execute_func [pconn, from];
    crucible_return (crucible_term {{ 0 : [32] }});
};

// Specification for s2n_socket_write_cork. The relevant part is
// that it increments the 'corked' ghost variable to 1 to
// indicate that the socket has been corked.
let s2n_socket_write_cork_spec = do {
    pconn <- crucible_alloc_readonly (llvm_struct "struct.s2n_connection");

    cork_val <- crucible_fresh_var "corked" (llvm_int 2);
    crucible_ghost_value corked cork_val;

    crucible_execute_func [pconn];

    crucible_ghost_value corked {{ cork_val + 1 }};

    crucible_return (crucible_term {{ 0 : [32] }});
};

// Specification for s2n_socket_was_corked.  We assume this function
// always returns 0 to indicate our assumption that the socket was
// uncorked initially. If it was corked, then the cork/uncork state
// machine would be bypassed, making verification moot.
let s2n_socket_was_corked_spec = do {
    pconn <- crucible_alloc_readonly (llvm_struct "struct.s2n_connection");

    crucible_execute_func [pconn];

    crucible_return (crucible_term {{ 0 : [32] }});
};


// Specification for s2n_socket_quickack. This is essentially
// a noop function that returns 0 from the perspective of our current proof
let s2n_socket_quickack_spec = do {
    pconn <- crucible_alloc_readonly (llvm_struct "struct.s2n_connection");

    crucible_execute_func [pconn];

    crucible_return (crucible_term {{ 0 : [32] }});
};


// Specification for s2n_connection_is_managed_corked. We assume it
// always returns 1 to reflect our assumption that the library is
// managing the corking and uncorking of the socket. Otherwise, the
//cork/uncork state machine would be bypassed making verification moot.
let s2n_connection_is_managed_corked_spec = do {
    pconn <- crucible_alloc_readonly (llvm_struct "struct.s2n_connection");

    crucible_execute_func [pconn];

    crucible_return (crucible_term {{ 1 : [32] }});
};