1
(* $Id: netmech_scram.mli 1560 2011-03-04 22:05:14Z gerd $ *)
3
(** SCRAM mechanism for authentication (RFC 5802) *)
5
(** This implements SCRAM-SHA-1 for GSSAPI. Other profiles may be added later.
7
As we do not implement SASLprep, usernames and passwords are restricted
11
type ptype = [ `GSSAPI ]
12
(** Currently only the variant for [`GSSAPI] is supported *)
14
type mechanism = [ `SHA_1 ]
18
mechanism : mechanism; (** Which mechanism *)
19
return_unknown_user : bool; (** Whether servers exhibit the fact that the
21
iteration_count_limit : int; (** Largest supported iteration number *)
28
| `Extensions_not_supported
30
| `Channel_bindings_dont_match
31
| `Server_does_support_channel_binding
32
| `Channel_binding_not_supported
33
| `Unsupported_channel_binding_type
35
| `Invalid_username_encoding
38
| `Extension of string
40
(** Error codes of this protocol *)
43
(** Session context for clients *)
47
(** Session context for servers *)
50
exception Invalid_encoding of string * string
51
(** Raised by clients when something cannot be decoded. First string
52
is an error message, the second string the raw message that cannot
56
exception Invalid_username_encoding of string * string
57
(** Raised by clients when the username does not match the requirements.
58
Arguments as for [Invalid_encoding].
61
exception Extensions_not_supported of string * string
62
(** Raised by clients when the server enables an unsupported extension.
63
Arguments as for [Invalid_encoding].
66
exception Protocol_error of string
67
(** Raised by clients when the server violates the protocol. The argument
71
exception Invalid_server_signature
72
(** Raised by clients when the signature sent by the server is invalid
73
(i.e. the server does not know the client password)
76
exception Server_error of server_error
77
(** Raised by clients when the server sent an error code *)
80
val profile : ?return_unknown_user:bool -> ?iteration_count_limit:int ->
82
(** Creates a profile *)
84
val string_of_server_error : server_error -> string
85
val server_error_of_string : string -> server_error
91
(** The idea is to create a client session [s] first. The functions
92
[client_emit_flag] and [client_recv_flag] indicate now whether
93
the client needs to emit a new message, or whether it needs to
94
receive a message, respectively. Emission is done by [client_emit_message],
95
reception by [client_recv_message]. If everything goes well, the
96
protocol state advances, and finally [client_finish_flag] is true.
97
This indicates that the client is authenticated and that the server
98
knows the client's password. If an error occurs, an exception is
99
raised (see above for possibilities), and [client_error_flag] signals
103
val create_client_session : profile -> string -> string -> client_session
104
(** [create_client_session p username password]: Creates a new client
105
session for profile [p] so that the client authenticates as user
106
[username], and proves its identify with the given [password].
109
val client_configure_channel_binding : client_session -> string -> unit
110
(** Instruct the client to require a channel binding. The passed string
111
is the [c] parameter (before encoding it via Base64. The function
112
needs to be called before sending the second message to the server.
113
It fails if called too late.
115
(* SASL: The string would have to include the gs2-header. For a SASL-enabled
116
profile we would need some additional functions
117
(client_negotiate_channel_binding).
120
val client_emit_flag : client_session -> bool
121
(** Whether [client_emit_message] can now be called *)
123
val client_recv_flag : client_session -> bool
124
(** Whether [client_recv_message] can now be called *)
126
val client_finish_flag : client_session -> bool
127
(** Whether the client is authenticated and the server verified *)
129
val client_error_flag : client_session -> bool
130
(** Whether an error occurred, and the protocol cannot advance anymore *)
132
val client_channel_binding : client_session -> string
133
(** Returns the channel binding ("" of none) *)
135
val client_emit_message : client_session -> string
136
(** Emits the next message to be sent to the server *)
138
val client_recv_message : client_session -> string -> unit
139
(** Receives the next message from the server *)
141
val client_protocol_key : client_session -> string option
142
(** The 128-bit protocol key for encrypting messages. This is available
143
as soon as the second client message is emitted.
146
val client_user_name : client_session -> string
149
val client_export : client_session -> string
150
val client_import : string -> client_session
151
(** Exports a client session as string, and imports the string again.
152
Only established sessions are allowed to be exported
153
(for which [client_finish_flag] is true).
155
The export format is just a marshalled Ocaml value.
161
(** The idea is to create a server session [s] first. The functions
162
[server_emit_flag] and [server_recv_flag] indicate now whether
163
the server needs to emit a new message, or whether it needs to
164
receive a message, respectively. Emission is done by [server_emit_message],
165
reception by [server_recv_message]. If everything goes well, the
166
protocol state advances, and finally [server_finish_flag] is true.
167
This indicates that the client could be authenticated.
169
If an error occurs, {b no} exception is raised, and the protocol
170
advances nevertheless, and finally the server sends an error token
171
to the client. After this, [server_error_flag] returns true.
175
val create_server_session :
176
profile -> (string -> string * string * int) -> server_session
177
(** [create_server_session p auth]: Creates a new server session with
178
profile [p] and authenticator function [auth].
180
The function is [auth] is called when the credentials of the
181
client have been received to check whether the client can be
182
authenticated. It is called as
185
let (salted_password, salt, iteration_count) = auth username
188
where [username] is the user name. The function can now raise
189
[Not_found] if the user is unknown, or it can return the
190
shown triple. Note that the cleartext password needs not to
191
be known. [salt] is a random string, and [iteration_count] a
192
security parameter that should be at least 4096. Whereas [salt]
193
should be different for each user, the [iteration_count] can be
194
chosen as a constant (e.g. 4096). Now [salted_password] can be
195
computed from the cleartext password and these two extra parameters.
196
See [salt_password] below.
199
val create_salt : unit -> string
200
(** Creates a random string suited as salt *)
202
val salt_password : string -> string -> int -> string
203
(** [let salted_password = salt_password password salt iteration_count]
205
As we do not implement [SASLprep] only passwords consisting of
206
US-ASCII characters are accepted ([Invalid_encoding] otherwise).
209
val server_emit_flag : server_session -> bool
210
(** Whether [server_emit_message] can now be called *)
212
val server_recv_flag : server_session -> bool
213
(** Whether [server_recv_message] can now be called *)
215
val server_finish_flag : server_session -> bool
216
(** Whether the client is authenticated *)
218
val server_error_flag : server_session -> bool
219
(** Whether an error occurred, and the protocol cannot advance anymore *)
221
val server_emit_message : server_session -> string
222
(** Emits the next message to be sent to the client *)
224
val server_recv_message : server_session -> string -> unit
225
(** Receives the next message from the client *)
227
val server_protocol_key : server_session -> string option
228
(** The 128-bit protocol key for encrypting messages. This is available
229
as soon as the second client message has been received.
232
val server_channel_binding : server_session -> string option
233
(** Returns the channel binding requirement (the "c" parameter). It is
234
up to the application to enforce the binding. This information is
235
available as soon as the second client message has been received
238
val server_user_name : server_session -> string option
239
(** The user name as transmitted from the client. This is returned here
240
even before the authentication is completed!
243
val server_export : server_session -> string
244
val server_import : string -> server_session
245
(** Exports a server session as string, and imports the string again.
246
Only established sessions are allowed to be exported
247
(for which [server_finish_flag] is true).
249
The export format is just a marshalled Ocaml value.
253
(** {2 Confidentiality} *)
260
(** The specific keys to use *)
262
(** This module implements AES in Ciphertext Stealing mode (see RFC 3962) *)
266
val encrypt : string -> string -> string
267
val encrypt_mstrings :
268
string -> Xdr_mstring.mstring list -> Xdr_mstring.mstring list
269
val decrypt : string -> string -> string
270
val decrypt_mstrings :
271
string -> Xdr_mstring.mstring list -> Xdr_mstring.mstring list
272
val tests : (string * string * string) list
273
val run_tests : unit -> bool
274
val run_mtests : unit -> bool
278
(** This is the cryptosystem as defined in RFC 3961, so far needed here.
279
This uses [AES_CTS] as cipher, and SHA1-96 for signing.
281
module Cryptosystem : sig
282
exception Integrity_error
284
val derive_keys : string -> int -> specific_keys
285
(** [derive_keys protocol_key usage]: Returns the specific keys for
286
this [protocol_key] and this [usage] numbers. See RFC 4121 for
287
applicable usage numbers
290
val encrypt_and_sign : specific_keys -> string -> string
291
(** Encrypts the plaintext message and adds a signature to the
294
Returns [ciphertext_with_signature].
297
val encrypt_and_sign_mstrings :
298
specific_keys -> Xdr_mstring.mstring list -> Xdr_mstring.mstring list
299
(** Same, but with data representation as [mstring list] *)
301
val decrypt_and_verify : specific_keys -> string -> string
302
(** Decrypts the ciphertext and verifies the attached signature.
303
Returns the restored plaintext.
305
For very short plaintexts (< 16 bytes) there will be some
306
padding at the end ("residue"), as returned as [ec] above.
307
We ignore this problem generally,
308
because GSS-API adds a 16-byte header to the plaintext anyway,
309
so these short messages do not occur.
311
If the signature is not valid, the exception [Integrity_error]
315
val decrypt_and_verify_mstrings :
316
specific_keys -> Xdr_mstring.mstring list -> Xdr_mstring.mstring list
317
(** Same, but with data representation as [mstring list] *)
319
val get_ec : specific_keys -> int -> int
320
(** [let ec = get_ec e_keys n]:
321
Returns the required value for the "extra count" field of
322
RFC 4121 if the plaintext message has size [n]. Here,
323
[n] is the size of the payload message plus the token
324
header of 16 bytes, i.e. the function is always called with
327
Here, the returned [ec] value is always 0.
330
val get_mic : specific_keys -> string -> string
331
(** Returns a message integrity code *)
333
val get_mic_mstrings :
334
specific_keys -> Xdr_mstring.mstring list -> string
335
(** Same, but with data representation as [mstring list] *)
340
val enable : bool ref
341
(** Enable debugging of this module *)