https_get.anubis
12.9 KB
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
The Anubis Project
Getting a document from the secured Web.
Copyright (c) Alain Prouté 2001.
Author: Alain Prouté
This file defines the function 'https_get' which retrieve a document from the world
wide web in secured mode (HTTPS). The function is analogous to 'http_get', to be found
in 'web/http_get.anubis'.
The function simulates the behavior of a browser, at least just what is needed to
retrieve the document. It does not display the document, but returns it (if found) in
the form of a string.
The function 'https_get' takes the following operands:
- the name of the server to which the request is to be sent,
- the name (including the path) of the document on this server,
- a list of headers to be added to mandatory standard headers,
- a list of 'arguments' to be sent as the body of the request (web arguments).
- an accept policy function (see below), for accepting X.509 certificates in case of
a problem.
The result returned by 'https_get' has the following type, which defines the problems
which may happen:
read tools/basis.anubis
read system/string.anubis
read html.anubis
read http_get_common.anubis
read common.anubis
public type HTTPS_GET_Result:
cannot_resolve_server_name(DNS_Result),
ssl_connect_error(SSLConnectError),
transmission_problem,
request_refused_by_server,
ok(String response,
List(HTTP_header) headers,
String document).
Cookies are among headers. See 'web/cookies.anubis' for cookies handling.
Note: The types 'DNS_Result' and 'SSLConnectError' are defined in 'predefined.anubis'.
public define HTTPS_GET_Result
https_get
(
String server_name,
String document_name,
List(HTTP_header) headers,
List(HTTP_argument) arguments,
(Maybe(X509)) -> Bool accept_policy
).
The same one without the 'headers' argument:
public define HTTPS_GET_Result
https_get
(
String server_name,
String document_name,
List(HTTP_argument) arguments,
(Maybe(X509)) -> Bool accept_policy
) = https_get(server_name,document_name,[],arguments,accept_policy).
The main difference with 'http_get' is the presence of the 'accept_policy'
argument. 'accept_policy' is the function which determines your personal policy for
accepting a server certificate, if it is the case that either this certificate is
invalid (or missing), or if its common name does not match the server name, that is to
say if 'open_SSL_connection' (defined in 'predefined.anubis') did not already accept
it.
'X509' is an 'opaque' type defined in 'predefined.anubis'. It is 'opaque' in the sens
that no alternative of this type is directly accessible to you (despite the fact that
the type is public).
An accept policy function takes (maybe) an X.509 certificate as its unique argument, so
that the decision may be taken with the suspect certificate at hand. It must return
'true' for accepting, and 'false' for refusing.
You may use the following default accept policy function:
public define Bool
default_accept_policy
(
Maybe(X509) suspect_certificate
) = false.
That is, never accept a certificate which cannot be successfully verified by
'open_SSL_connection'. Notice that this is not a paranoid behavior, but a normal
behavior. Nevertheless, you still have the possibility to weaken this behavior by
using another accept policy function. Be very careful when writing this function,
because this may weaken your security. This function may for example show the
certificate and ask for user input for accepting it. It may also check the certificate
fingerprint against a data base, etc...
Another accept policy function is defined in this file:
public define Bool
command_line_accept_policy
(
Maybe(X509) suspect_certificate
).
It is used by the command line module 'https_get.adm'. If the certificate is not
accepted by 'open_SSL_connection', this function prints the certificate on the screen,
and ask the user for acceptation. It also asks the user for accepting the certificate
for ever.
It is likely that you will need an accept policy function of your own. See the
definition of 'command_line_accept_policy' below for information and
'predefined.anubis' for the tools enabling the manipulation of X.509 certificates.
Certificates that you trust are stored into the directory declared under the symbol
'ca' (for 'Certificate Authorities') in your configuration file. Any certificate
present in this directory is trusted without any condition.
This file defines the module 'https_get' to be used directly from the command line. To
learn about the syntax, just type 'https_get' at the system prompt, or have a look at
the end of this file.
--- That's all for public definitions. ------------------------------------------------
define Maybe(String)
receive_text_chunk
(
SSL_Connection conn
) =
read(conn,100,1000).
define HTTPS_GET_Result
receive
(
SSL_Connection conn,
String headers,
String text_so_far,
Bool double_crlf_seen
) =
if receive_text_chunk(conn) is
{
failure then if separate_headers(headers) is
{
[ ] then ok("",[],text_so_far),
[h . t] then if h is http_header(a,b) then ok(a,t,text_so_far)
},
success(s) then
if s = ""
then if separate_headers(headers) is
{
[ ] then ok("",[],text_so_far),
[h . t] then if h is http_header(a,b) then ok(a,t,text_so_far)
}
else with new_s = text_so_far+s,
if double_crlf_seen
then receive(conn,headers,new_s,true)
else if has_double_crlf(new_s) is
{
failure then receive(conn,headers,new_s,false),
success(n) then
if sub_string(new_s,n+4,length(new_s)-n-4) is
{
failure then should_not_happen(transmission_problem),
success(s1) then
if sub_string(new_s,0,n) is
{
failure then should_not_happen(transmission_problem),
success(h) then receive(conn,h,s1,true)
}
}
}
}.
The next function has a valid SSL connection to the server, and tries to retrieve the
document.
define HTTPS_GET_Result
https_get
(
Bool print_all,
SSL_Connection conn,
String server_name,
String document_name,
List(HTTP_header) headers,
List(HTTP_argument) arguments
) =
//
// Send the HTTP request, and receive the answer:
//
with body = format_http_args(arguments),
with request = (if arguments = [] then "GET " else "POST ")
+ document_name + " HTTP/1.0" + crlf +
"Host: " + server_name + crlf +
"Accept-Charset: iso-8859-1,*,utf-8" + crlf +
(if arguments = [] then ""
else "Content-type: application/x-www-form-urlencoded" + crlf +
"Content-length: " + to_decimal(length(body))+ crlf) +
format_headers(headers) +
crlf +
body,
(if print_all then
(
print("Sending request:\n");
print(request);
print("\n")
) else unique);
if write(conn,request) is
{
failure then transmission_problem,
success(_) then receive(conn,"","",false)
}.
The next function retrieves the document using the numerical (resolved) server address.
define HTTPS_GET_Result
https_get
(
Bool print_all,
Word32 server_addr,
Word32 server_port,
String server_name,
String document_name,
List(HTTP_header) headers,
List(HTTP_argument) arguments,
(Maybe(X509)) -> Bool accept_policy
) =
if open_SSL_connection(server_name,server_addr,server_port,accept_policy) is
{
error(msg) then ssl_connect_error(msg),
ok(conn) then https_get(print_all,conn,server_name,document_name,headers,arguments)
}.
define HTTPS_GET_Result
https_get
(
Bool print_all,
String server_name,
String document_name,
List(HTTP_header) headers,
List(HTTP_argument) arguments,
(Maybe(X509)) -> Bool accept_policy
) =
if separate_name_port(server_name,443) is (name,port) then
//
// resolve server name and call 'https_get' with numeric server address:
//
with a = dns(name),
if a is ok(addr)
then https_get(print_all,addr,port,name,document_name,headers,arguments,accept_policy)
else cannot_resolve_server_name(a).
Now, here is our public tool:
public define HTTPS_GET_Result
https_get
(
String server_name,
String document_name,
List(HTTP_header) headers,
List(HTTP_argument) arguments,
(Maybe(X509)) -> Bool accept_policy
) = https_get(false,server_name,document_name,headers,arguments,accept_policy).
Finally, we construct the command line executable module 'https_get.adm':
define One
syntax_https_get =
print("\nUsage: https_get <server> <document> [options] =<header> <value> ... <arg> <value> ...\n");
print(" Options are:\n");
print(" -print_all print request, response line, headers and document\n");
print(" (default is to print only the document)\n").
Below is our accept policy function for the command line module. This function may
serve as a model for your own accept policy function.
public define Bool
command_line_accept_policy
(
Maybe(X509) mbcert
) =
if mbcert is
{
failure then
print("No server certificate or invalid server certificate.\n");
print("Do you want to trust this site anyway ? [Y/N]\n");
yes, // this is the same as 'if yes then true else false'
success(cert) then
print(to_string(cert));
print("\nDo you want to accept the above certificate ? [Y/N]\n");
if yes
then (
print("Do you want to accept this certificate for ever ? [Y/N]\n");
if yes
then (if trust_for_ever(cert) is
{
ca_directory_not_found then print("'ca' directory not found.\n"),
cannot_create_file then print("cannot create file.\n"),
cannot_create_symbolic_link then print("cannot create symbolic link.\n"),
write_error then print("write error.\n"),
ok then unique
}; true)
else true
)
else false
}.
global define One
https_get
(
List(String) args
) =
if args is
{
[ ] then syntax_https_get,
[server . t] then if t is
{
[ ] then syntax_https_get,
[document . rest] then
with print_all = member(rest,"-print_all"),
headers = get_headers(rest),
arguments = get_arguments(rest),
if https_get(print_all,server,document,headers,arguments,command_line_accept_policy) is
{
cannot_resolve_server_name(dns_error) then
print("Cannot resolve server name: " + format(dns_error) + ".\n"),
ssl_connect_error(connect_error) then
print("SSL connect error: " + format(connect_error) + ".\n"),
transmission_problem then
print("Transmission problem.\n"),
request_refused_by_server then
print("The request has been refused by server: " + server + ".\n"),
ok(response,headers1,document1) then
(
if print_all
then (
print("\n----- response ----\n");
print(response);
print("\n----- headers -----\n");
print_headers(headers1);
print("----- document ----\n")
) else unique
);
print(document1) // on the screen (use a redirection to get it in a file)
}
}
}.