root/trunk/thirdparty/cl+ssl/ffi.lisp

Revision 2996, 9.3 kB (checked in by hans, 9 months ago)

Update CL+SSL

Line 
1 ;;; Copyright (C) 2001, 2003  Eric Marsden
2 ;;; Copyright (C) 2005  David Lichteblau
3 ;;; "the conditions and ENSURE-SSL-FUNCALL are by Jochen Schmidt."
4 ;;;
5 ;;; See LICENSE for details.
6
7 (eval-when (:compile-toplevel)
8   (declaim
9    (optimize (speed 3) (space 1) (safety 1) (debug 0) (compilation-speed 0))))
10
11 (in-package :cl+ssl)
12
13 ;;; Global state
14 ;;;
15 (defvar *ssl-global-context* nil)
16 (defvar *ssl-global-method* nil)
17 (defvar *bio-lisp-method* nil)
18
19 (defparameter *blockp* t)
20 (defparameter *partial-read-p* nil)
21
22 (defun ssl-initialized-p ()
23   (and *ssl-global-context* *ssl-global-method*))
24
25
26 ;;; Constants
27 ;;;
28 (defconstant +random-entropy+ 256)
29
30 (defconstant +ssl-filetype-pem+ 1)
31 (defconstant +ssl-filetype-asn1+ 2)
32 (defconstant +ssl-filetype-default+ 3)
33
34 (defconstant +SSL_CTRL_SET_SESS_CACHE_MODE+ 44)
35 (defconstant +SSL_CTRL_MODE+ 33)
36
37 (defconstant +SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER+ 2)
38
39 ;;; Misc
40 ;;;
41 (defmacro while (cond &body body)
42   `(do () ((not ,cond)) ,@body))
43
44
45 ;;; Function definitions
46 ;;;
47 (declaim (inline ssl-write ssl-read ssl-connect ssl-accept))
48
49 (cffi:defctype ssl-method :pointer)
50 (cffi:defctype ssl-ctx :pointer)
51 (cffi:defctype ssl-pointer :pointer)
52
53 (cffi:defcfun ("SSL_get_version" ssl-get-version)
54     :string
55   (ssl ssl-pointer))
56 (cffi:defcfun ("SSL_load_error_strings" ssl-load-error-strings)
57     :void)
58 (cffi:defcfun ("SSL_library_init" ssl-library-init)
59     :int)
60 (cffi:defcfun ("SSLv2_client_method" ssl-v2-client-method)
61     ssl-method)
62 (cffi:defcfun ("SSLv23_client_method" ssl-v23-client-method)
63     ssl-method)
64 (cffi:defcfun ("SSLv23_server_method" ssl-v23-server-method)
65     ssl-method)
66 (cffi:defcfun ("SSLv23_method" ssl-v23-method)
67     ssl-method)
68 (cffi:defcfun ("SSLv3_client_method" ssl-v3-client-method)
69     ssl-method)
70 (cffi:defcfun ("SSLv3_server_method" ssl-v3-server-method)
71     ssl-method)
72 (cffi:defcfun ("SSLv3_method" ssl-v3-method)
73     ssl-method)
74 (cffi:defcfun ("TLSv1_client_method" ssl-TLSv1-client-method)
75     ssl-method)
76 (cffi:defcfun ("TLSv1_server_method" ssl-TLSv1-server-method)
77     ssl-method)
78 (cffi:defcfun ("TLSv1_method" ssl-TLSv1-method)
79     ssl-method)
80
81 (cffi:defcfun ("SSL_CTX_new" ssl-ctx-new)
82     ssl-ctx
83   (method ssl-method))
84 (cffi:defcfun ("SSL_new" ssl-new)
85     ssl-pointer
86   (ctx ssl-ctx))
87 (cffi:defcfun ("SSL_get_fd" ssl-get-fd)
88     :int
89   (ssl ssl-pointer))
90 (cffi:defcfun ("SSL_set_fd" ssl-set-fd)
91     :int
92   (ssl ssl-pointer)
93   (fd :int))
94 (cffi:defcfun ("SSL_set_bio" ssl-set-bio)
95     :void
96   (ssl ssl-pointer)
97   (rbio :pointer)
98   (wbio :pointer))
99 (cffi:defcfun ("SSL_get_error" ssl-get-error)
100     :int
101   (ssl ssl-pointer)
102   (ret :int))
103 (cffi:defcfun ("SSL_set_connect_state" ssl-set-connect-state)
104     :void
105   (ssl ssl-pointer))
106 (cffi:defcfun ("SSL_set_accept_state" ssl-set-accept-state)
107     :void
108   (ssl ssl-pointer))
109 (cffi:defcfun ("SSL_connect" ssl-connect)
110     :int
111   (ssl ssl-pointer))
112 (cffi:defcfun ("SSL_accept" ssl-accept)
113     :int
114   (ssl ssl-pointer))
115 (cffi:defcfun ("SSL_write" ssl-write)
116     :int
117   (ssl ssl-pointer)
118   (buf :pointer)
119   (num :int))
120 (cffi:defcfun ("SSL_read" ssl-read)
121     :int
122   (ssl ssl-pointer)
123   (buf :pointer)
124   (num :int))
125 (cffi:defcfun ("SSL_shutdown" ssh-shutdown)
126     :void
127   (ssl ssl-pointer))
128 (cffi:defcfun ("SSL_free" ssl-free)
129     :void
130   (ssl ssl-pointer))
131 (cffi:defcfun ("SSL_CTX_free" ssl-ctx-free)
132     :void
133   (ctx ssl-ctx))
134 (cffi:defcfun ("RAND_seed" rand-seed)
135     :void
136   (buf :pointer)
137   (num :int))
138 (cffi:defcfun ("BIO_ctrl" bio-set-fd)
139     :long
140   (bio :pointer)
141   (cmd :int)
142   (larg :long)
143   (parg :pointer))
144 (cffi:defcfun ("BIO_new_socket" bio-new-socket)
145     :pointer
146   (fd :int)
147   (close-flag :int))
148 (cffi:defcfun ("BIO_new" bio-new)
149     :pointer
150   (method :pointer))
151
152 (cffi:defcfun ("ERR_get_error" err-get-error)
153     :unsigned-long)
154 (cffi:defcfun ("ERR_error_string" err-error-string)
155     :string
156   (e :unsigned-long)
157   (buf :pointer))
158
159 (cffi:defcfun ("SSL_set_cipher_list" ssl-set-cipher-list)
160     :int
161   (ssl ssl-pointer)
162   (str :string))
163 (cffi:defcfun ("SSL_use_RSAPrivateKey_file" ssl-use-rsa-privatekey-file)
164     :int
165   (ssl ssl-pointer)
166   (str :string)
167   ;; either +ssl-filetype-pem+ or +ssl-filetype-asn1+
168   (type :int))
169 (cffi:defcfun
170     ("SSL_CTX_use_RSAPrivateKey_file" ssl-ctx-use-rsa-privatekey-file)
171     :int
172   (ctx ssl-ctx)
173   (type :int))
174 (cffi:defcfun ("SSL_use_certificate_file" ssl-use-certificate-file)
175     :int
176   (ssl ssl-pointer)
177   (str :string)
178   (type :int))
179 (cffi:defcfun ("SSL_CTX_load_verify_locations" ssl-ctx-load-verify-locations)
180     :int
181   (ctx ssl-ctx)
182   (CAfile :string)
183   (CApath :string))
184 (cffi:defcfun ("SSL_CTX_set_client_CA_list" ssl-ctx-set-client-ca-list)
185     :void
186   (ctx ssl-ctx)
187   (list ssl-pointer))
188 (cffi:defcfun ("SSL_load_client_CA_file" ssl-load-client-ca-file)
189     ssl-pointer
190   (file :string))
191
192 (cffi:defcfun ("SSL_CTX_ctrl" ssl-ctx-ctrl)
193     :long
194   (ctx ssl-ctx)
195   (cmd :int)
196   (larg :long)
197   (parg :long))
198
199
200 ;;; Funcall wrapper
201 ;;;
202 (defvar *socket*)
203
204 (declaim (inline ensure-ssl-funcall))
205 (defun ensure-ssl-funcall (stream handle func &rest args)
206   (loop
207      (let ((nbytes
208             (let ((*socket* stream))    ;for Lisp-BIO callbacks
209               (apply func args))))
210        (when (plusp nbytes)
211          (return nbytes))
212        (let ((error (ssl-get-error handle nbytes)))
213          (case error
214            (#.+ssl-error-want-read+
215             (input-wait stream
216                         (ssl-get-fd handle)
217                         (ssl-stream-deadline stream)))
218            (#.+ssl-error-want-write+
219             (output-wait stream
220                          (ssl-get-fd handle)
221                          (ssl-stream-deadline stream)))
222            (t
223             (ssl-signal-error handle func error nbytes)))))))
224
225
226 ;;; Waiting for output to be possible
227
228 #+clozure-common-lisp
229 (defun milliseconds-until-deadline (deadline stream)
230   (let* ((now (get-internal-real-time)))
231     (if (> now deadline)
232         (error 'ccl::communication-deadline-expired :stream stream)
233         (values
234          (round (- deadline now) (/ internal-time-units-per-second 1000))))))
235
236 #+clozure-common-lisp
237 (defun output-wait (stream fd deadline)
238   (unless deadline
239     (setf deadline (stream-deadline (ssl-stream-socket stream))))
240   (let* ((timeout
241           (if deadline
242               (milliseconds-until-deadline deadline stream)
243               nil)))
244     (multiple-value-bind (win timedout error)
245         (ccl::process-output-wait fd timeout)
246       (unless win
247         (if timedout
248             (error 'ccl::communication-deadline-expired :stream stream)
249             (ccl::stream-io-error stream (- error) "write"))))))
250
251 #+sbcl
252 (defun output-wait (stream fd deadline)
253   (declare (ignore stream))
254   (let ((timeout
255          ;; *deadline* is handled by wait-until-fd-usable automatically,
256          ;; but we need to turn a user-specified deadline into a timeout
257          (when deadline
258            (/ (- deadline (get-internal-real-time))
259               internal-time-units-per-second))))
260     (sb-sys:wait-until-fd-usable fd :output timeout)))
261
262 #-(or clozure-common-lisp sbcl)
263 (defun output-wait (stream fd deadline)
264   (declare (ignore stream fd deadline))
265   ;; This situation means that the lisp set our fd to non-blocking mode,
266   ;; and streams.lisp didn't know how to undo that.
267   (warn "non-blocking stream encountered unexpectedly"))
268
269
270 ;;; Waiting for input to be possible
271
272 #+clozure-common-lisp
273 (defun input-wait (stream fd deadline)
274   (unless deadline
275     (setf deadline (stream-deadline (ssl-stream-socket stream))))
276   (let* ((timeout
277           (if deadline
278               (milliseconds-until-deadline deadline stream)
279               nil)))
280     (multiple-value-bind (win timedout error)
281         (ccl::process-input-wait fd timeout)
282       (unless win
283         (if timedout
284             (error 'ccl::communication-deadline-expired :stream stream)
285             (ccl::stream-io-error stream (- error) "read"))))))
286
287 #+sbcl
288 (defun input-wait (stream fd deadline)
289   (declare (ignore stream))
290   (let ((timeout
291          ;; *deadline* is handled by wait-until-fd-usable automatically,
292          ;; but we need to turn a user-specified deadline into a timeout
293          (when deadline
294            (/ (- deadline (get-internal-real-time))
295               internal-time-units-per-second))))
296     (sb-sys:wait-until-fd-usable fd :input timeout)))
297
298 #-(or clozure-common-lisp sbcl)
299 (defun input-wait (stream fd deadline)
300   (declare (ignore stream fd deadline))
301   ;; This situation means that the lisp set our fd to non-blocking mode,
302   ;; and streams.lisp didn't know how to undo that.
303   (warn "non-blocking stream encountered unexpectedly"))
304
305
306 ;;; Initialization
307 ;;;
308 (defun init-prng ()
309   ;; this initialization of random entropy is not necessary on
310   ;; Linux, since the OpenSSL library automatically reads from
311   ;; /dev/urandom if it exists. On Solaris it is necessary.
312   (let ((buf (cffi-sys::make-shareable-byte-vector +random-entropy+)))
313     (dotimes (i +random-entropy+)
314       (setf (elt buf i) (random 256)))
315     (cffi-sys::with-pointer-to-vector-data (ptr buf)
316       (rand-seed ptr +random-entropy+))))
317
318 (defun ssl-ctx-set-session-cache-mode (ctx mode)
319   (ssl-ctx-ctrl ctx +SSL_CTRL_SET_SESS_CACHE_MODE+ mode 0))
320
321 (defun initialize (&optional (method 'ssl-v23-method))
322   (setf *bio-lisp-method* (make-bio-lisp-method))
323   (ssl-load-error-strings)
324   (ssl-library-init)
325   (init-prng)
326   (setf *ssl-global-method* (funcall method))
327   (setf *ssl-global-context* (ssl-ctx-new *ssl-global-method*))
328   (ssl-ctx-set-session-cache-mode *ssl-global-context* 3))
329
330 (defun ensure-initialized (&optional (method 'ssl-v23-method))
331   (unless (ssl-initialized-p)
332     (initialize method))
333   (unless *bio-lisp-method*
334     (setf *bio-lisp-method* (make-bio-lisp-method))))
335
336 (defun reload ()
337   (cffi:load-foreign-library 'libssl)
338   (cffi:load-foreign-library 'libeay32)
339   (setf *ssl-global-context* nil)
340   (setf *ssl-global-method* nil))
Note: See TracBrowser for help on using the browser.