1 (* HCoop
Domtool (http
://hcoop
.sourceforge
.net
/)
2 * Copyright (c
) 2006, Adam Chlipala
4 * This program is free software
; you can redistribute it
and/or
5 * modify it under the terms
of the GNU General Public License
6 * as published by the Free Software Foundation
; either version
2
7 * of the License
, or (at your option
) any later version
.
9 * This program is distributed
in the hope that it will be useful
,
10 * but WITHOUT ANY WARRANTY
; without even the implied warranty
of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE
. See the
12 * GNU General Public License for more details
.
14 * You should have received a copy
of the GNU General Public License
15 * along
with this program
; if not
, write to the Free Software
16 * Foundation
, Inc
., 51 Franklin Street
, Fifth Floor
, Boston
, MA
02110-1301, USA
.
21 structure OpenSSL
:> OPENSSL
= struct
23 val () = (F_OpenSSL_SML_init
.f
' ();
24 F_OpenSSL_SML_load_error_strings
.f
' ();
25 F_OpenSSL_SML_load_BIO_strings
.f
' ())
27 exception OpenSSL
of string
29 type context
= (ST_ssl_ctx_st
.tag
, C_Int
.rw
) C_Int
.su_obj C_Int
.ptr
'
30 type bio
= (ST_bio_st
.tag
, C_Int
.rw
) C_Int
.su_obj C_Int
.ptr
'
35 val err
= F_OpenSSL_SML_get_error
.f ()
37 val lib
= F_OpenSSL_SML_lib_error_string
.f err
38 val func
= F_OpenSSL_SML_func_error_string
.f err
39 val reason
= F_OpenSSL_SML_reason_error_string
.f err
43 if C
.Ptr
.isNull lib
then
46 (print (ZString
.toML lib
);
48 if C
.Ptr
.isNull func
then
51 (print (ZString
.toML func
);
53 if C
.Ptr
.isNull reason
then
56 print (ZString
.toML reason
);
60 val readBuf
: (C
.uchar
, C
.rw
) C
.obj C
.ptr
' = C
.alloc
' C
.S
.uchar (Word.fromInt Config
.bufSize
)
61 val bufSize
= Int32
.fromInt Config
.bufSize
62 val one
= Int32
.fromInt
1
63 val four
= Int32
.fromInt
4
65 val eight
= Word.fromInt
8
66 val sixteen
= Word.fromInt
16
67 val twentyfour
= Word.fromInt
24
69 val mask1
= Word32
.fromInt
255
73 val r
= F_OpenSSL_SML_read
.f
' (bio
, C
.Ptr
.inject
' readBuf
, one
)
79 raise OpenSSL
"BIO_read failed")
81 SOME (chr (Compat
.Char.toInt (C
.Get
.uchar
'
82 (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 0)))))
85 val charToWord
= Word32
.fromLargeWord
o Compat
.Char.toLargeWord
89 val r
= F_OpenSSL_SML_read
.f
' (bio
, C
.Ptr
.inject
' readBuf
, four
)
95 raise OpenSSL
"BIO_read failed")
99 (charToWord (C
.Get
.uchar
' (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 0))),
101 (Word32
.<< (charToWord (C
.Get
.uchar
' (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 1))),
104 (Word32
.<< (charToWord (C
.Get
.uchar
' (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 2))),
106 Word32
.<< (charToWord (C
.Get
.uchar
' (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 3))),
110 fun readLen (bio
, len
) =
113 if len
> Config
.bufSize
then
114 C
.alloc
' C
.S
.uchar (Word.fromInt len
)
119 if len
> Config
.bufSize
then
124 fun loop (buf
', needed
) =
126 val r
= F_OpenSSL_SML_read
.f
' (bio
, C
.Ptr
.inject
' buf
, Int32
.fromInt len
)
133 raise OpenSSL
"BIO_read failed")
134 else if r
= needed
then
135 SOME (CharVector
.tabulate (Int32
.toInt needed
,
136 fn i
=> chr (Compat
.Char.toInt (C
.Get
.uchar
'
137 (C
.Ptr
.sub
' C
.S
.uchar (buf
, i
))))))
139 loop (C
.Ptr
.|
+! C
.S
.uchar (buf
', Int32
.toInt r
), needed
- r
)
142 loop (buf
, Int32
.fromInt len
)
148 val r
= F_OpenSSL_SML_read
.f
' (bio
, C
.Ptr
.inject
' readBuf
, bufSize
)
154 raise OpenSSL
"BIO_read failed")
156 SOME (CharVector
.tabulate (Int32
.toInt r
,
157 fn i
=> chr (Compat
.Char.toInt (C
.Get
.uchar
'
158 (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, i
))))))
164 | SOME len
=> readLen (bio
, len
)
166 fun writeChar (bio
, ch
) =
168 val _
= C
.Set
.uchar
' (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 0),
169 Compat
.Char.fromInt (ord ch
))
173 val r
= F_OpenSSL_SML_write
.f
' (bio
, C
.Ptr
.inject
' readBuf
, one
)
178 (ssl_err
"BIO_write";
179 raise OpenSSL
"BIO_write")
187 val wordToChar
= Compat
.Char.fromLargeWord
o Word32
.toLargeWord
189 fun writeInt (bio
, n
) =
191 val w
= Word32
.fromInt n
193 val _
= (C
.Set
.uchar
' (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 0),
194 wordToChar (Word32
.andb (w
, mask1
)));
195 C
.Set
.uchar
' (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 1),
196 wordToChar (Word32
.andb (Word32
.>> (w
, eight
), mask1
)));
197 C
.Set
.uchar
' (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 2),
198 wordToChar (Word32
.andb (Word32
.>> (w
, sixteen
), mask1
)));
199 C
.Set
.uchar
' (C
.Ptr
.sub
' C
.S
.uchar (readBuf
, 3),
200 wordToChar (Word32
.andb (Word32
.>> (w
, twentyfour
), mask1
))))
202 fun trier (buf
, count
) =
204 val r
= F_OpenSSL_SML_write
.f
' (bio
, C
.Ptr
.inject
' buf
, count
)
207 (ssl_err
"BIO_write";
208 raise OpenSSL
"BIO_write")
209 else if r
= count
then
212 trier (C
.Ptr
.|
+! C
.S
.uchar (buf
, Int32
.toInt r
), count
- r
)
218 fun writeString
' (bio
, s
) =
220 val buf
= ZString
.dupML
' s
222 if F_OpenSSL_SML_puts
.f
' (bio
, buf
) <= 0 then
225 raise OpenSSL
"BIO_puts")
230 fun writeString (bio
, s
) =
231 (writeInt (bio
, size s
);
232 writeString
' (bio
, s
))
234 fun context
printErr (chain
, key
, root
) =
236 val context
= F_OpenSSL_SML_CTX_new
.f
' (F_OpenSSL_SML_SSLv23_method
.f
' ())
238 if C
.Ptr
.isNull
' context
then
239 (if printErr
then ssl_err
"Error creating SSL context" else ();
240 raise OpenSSL
"Can't create SSL context")
241 else if F_OpenSSL_SML_use_certificate_chain_file
.f
' (context
,
242 ZString
.dupML
' chain
)
244 (if printErr
then ssl_err
"Error using certificate chain" else ();
245 F_OpenSSL_SML_CTX_free
.f
' context
;
246 raise OpenSSL
"Can't load certificate chain")
247 else if F_OpenSSL_SML_use_PrivateKey_file
.f
' (context
,
250 (if printErr
then ssl_err
"Error using private key" else ();
251 F_OpenSSL_SML_CTX_free
.f
' context
;
252 raise OpenSSL
"Can't load private key")
253 else if F_OpenSSL_SML_load_verify_locations
.f
' (context
,
255 C
.Ptr
.null
') = 0 then
256 (if printErr
then ssl_err
"Error loading trust store" else ();
257 F_OpenSSL_SML_CTX_free
.f
' context
;
258 raise OpenSSL
"Can't load trust store")
263 fun connect (context
, hostname
) =
265 val bio
= F_OpenSSL_SML_new_ssl_connect
.f
' context
267 if C
.Ptr
.isNull
' bio
then
268 (ssl_err ("Error initializating connection to " ^ hostname
);
269 F_OpenSSL_SML_free_all
.f
' bio
;
270 raise OpenSSL
"Can't initialize connection")
271 else if F_OpenSSL_SML_set_conn_hostname
.f
' (bio
, ZString
.dupML
' hostname
) = 0 then
272 (ssl_err ("Error setting hostname: " ^ hostname
);
273 F_OpenSSL_SML_free_all
.f
' bio
;
274 raise OpenSSL
"Can't set hostname")
275 else if F_OpenSSL_SML_do_connect
.f
' bio
<= 0 then
276 (ssl_err ("Error connecting to " ^ hostname
);
277 F_OpenSSL_SML_free_all
.f
' bio
;
278 raise OpenSSL
"Can't connect")
283 fun close bio
= F_OpenSSL_SML_free_all
.f
' bio
285 fun listen (context
, port
) =
287 val port
= ZString
.dupML
' (Int.toString port
)
288 val listener
= F_OpenSSL_SML_new_accept
.f
' (context
, port
)
291 if C
.Ptr
.isNull
' listener
then
292 (ssl_err
"Null listener";
293 raise OpenSSL
"Null listener")
294 else if F_OpenSSL_SML_do_accept
.f
' listener
<= 0 then
295 (ssl_err
"Error initializing listener";
297 raise OpenSSL
"Can't initialize listener")
304 fun accept listener
=
305 if F_OpenSSL_SML_do_accept
.f
' listener
<= 0 then
309 val bio
= F_OpenSSL_SML_pop
.f
' listener
311 if C
.Ptr
.isNull
' bio
then
312 (ssl_err
"Null accepted";
313 raise OpenSSL
"Null accepted")
314 else if F_OpenSSL_SML_do_handshake
.f
' bio
<= 0 then
315 (ssl_err
"Handshake failed";
316 raise OpenSSL
"Handshake failed")
323 val ssl
= F_OpenSSL_SML_get_ssl
.f
' bio
324 val _
= if C
.Ptr
.isNull
' ssl
then
325 raise OpenSSL
"Null SSL"
328 val subj
= F_OpenSSL_SML_get_peer_name
.f
' ssl
330 if C
.Ptr
.isNull
' subj
then
331 raise OpenSSL
"Null CN result"