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

Revision 4020, 9.9 kB (checked in by hans, 2 months ago)

update from upstream

Line 
1 ;;; Copyright (C) 2001, 2003  Eric Marsden
2 ;;; Copyright (C) 2005  David Lichteblau
3 ;;; Copyright (C) 2007  Pixel // pinterface
4 ;;; "the conditions and ENSURE-SSL-FUNCALL are by Jochen Schmidt."
5 ;;;
6 ;;; See LICENSE for details.
7
8 (eval-when (:compile-toplevel)
9   (declaim
10    (optimize (speed 3) (space 1) (safety 1) (debug 0) (compilation-speed 0))))
11
12 (in-package :cl+ssl)
13
14 (defclass ssl-stream
15     (fundamental-binary-input-stream
16      fundamental-binary-output-stream
17      trivial-gray-stream-mixin)
18   ((ssl-stream-socket
19     :initarg :socket
20     :accessor ssl-stream-socket)
21    (close-callback
22     :initarg :close-callback
23     :accessor ssl-close-callback)
24    (handle
25     :initform nil
26     :accessor ssl-stream-handle)
27    (deadline
28     :initform nil
29     :initarg :deadline
30     :accessor ssl-stream-deadline)
31    (output-buffer
32     :initform (make-buffer +initial-buffer-size+)
33     :accessor ssl-stream-output-buffer)
34    (output-pointer
35     :initform 0
36     :accessor ssl-stream-output-pointer)
37    (input-buffer
38     :initform (make-buffer +initial-buffer-size+)
39     :accessor ssl-stream-input-buffer)
40    (peeked-byte
41     :initform nil
42     :accessor ssl-stream-peeked-byte)))
43
44 (defmethod print-object ((object ssl-stream) stream)
45   (print-unreadable-object (object stream :type t)
46     (format stream "for ~A" (ssl-stream-socket object))))
47
48 (defclass ssl-server-stream (ssl-stream)
49   ((certificate
50     :initarg :certificate
51     :accessor ssl-stream-certificate)
52    (key
53     :initarg :key
54     :accessor ssl-stream-key)))
55
56 (defmethod stream-element-type ((stream ssl-stream))
57   '(unsigned-byte 8))
58
59 (defmethod close ((stream ssl-stream) &key abort)
60   (cond
61     ((ssl-stream-handle stream)
62      (unless abort
63        (force-output stream))
64      (ssl-free (ssl-stream-handle stream))
65      (setf (ssl-stream-handle stream) nil)
66      (when (streamp (ssl-stream-socket stream))
67        (close (ssl-stream-socket stream)))
68      (when (functionp (ssl-close-callback stream))
69        (funcall (ssl-close-callback stream)))
70      t)
71     (t
72      nil)))
73
74 (defmethod open-stream-p ((stream ssl-stream))
75   (and (ssl-stream-handle stream) t))
76
77 (defmethod stream-listen ((stream ssl-stream))
78   (or (ssl-stream-peeked-byte stream)
79       (setf (ssl-stream-peeked-byte stream)
80             (let* ((*blockp* nil)
81                    (b (stream-read-byte stream)))
82               (if (eql b :eof) nil b)))))
83
84 (defmethod stream-read-byte ((stream ssl-stream))
85   (or (ssl-stream-peeked-byte stream)
86       (let ((buf (ssl-stream-input-buffer stream)))
87         (handler-case
88             (with-pointer-to-vector-data (ptr buf)
89               (ensure-ssl-funcall stream
90                                   (ssl-stream-handle stream)
91                                   #'ssl-read
92                                   (ssl-stream-handle stream)
93                                   ptr
94                                   1)
95               (buffer-elt buf 0))
96           (ssl-error-zero-return ()     ;SSL_read returns 0 on end-of-file
97             :eof)))))
98
99 (defmethod stream-read-sequence ((stream ssl-stream) thing start end &key)
100   (check-type thing (simple-array (unsigned-byte 8) (*)))
101   (when (and (< start end) (ssl-stream-peeked-byte stream))
102     (setf (elt thing start) (ssl-stream-peeked-byte stream))
103     (setf (ssl-stream-peeked-byte stream) nil)
104     (incf start))
105   (let ((buf (ssl-stream-input-buffer stream)))
106     (loop
107         for length = (min (- end start) (buffer-length buf))
108         while (plusp length)
109         do
110           (handler-case
111               (with-pointer-to-vector-data (ptr buf)
112                 (ensure-ssl-funcall stream
113                                     (ssl-stream-handle stream)
114                                     #'ssl-read
115                                     (ssl-stream-handle stream)
116                                     ptr
117                                     length)
118                 (v/b-replace thing buf :start1 start :end1 (+ start length))
119                 (incf start length))
120             (ssl-error-zero-return ()   ;SSL_read returns 0 on end-of-file
121               (return))))
122     ;; fixme: kein out-of-file wenn (zerop start)?
123     start))
124
125 (defmethod stream-write-byte ((stream ssl-stream) b)
126   (let ((buf (ssl-stream-output-buffer stream)))
127     (when (eql (buffer-length buf) (ssl-stream-output-pointer stream))
128       (force-output stream))
129     (setf (buffer-elt buf (ssl-stream-output-pointer stream)) b)
130     (incf (ssl-stream-output-pointer stream)))
131   b)
132
133 (defmethod stream-write-sequence ((stream ssl-stream) thing start end &key)
134   (check-type thing (simple-array (unsigned-byte 8) (*)))
135   (let ((buf (ssl-stream-output-buffer stream)))
136     (when (> (+ (- end start) (ssl-stream-output-pointer stream)) (buffer-length buf))
137       ;; not enough space left?  flush buffer.
138       (force-output stream)
139       ;; still doesn't fit?
140       (while (> (- end start) (buffer-length buf))
141         (b/v-replace buf thing :start2 start)
142         (incf start (buffer-length buf))
143         (setf (ssl-stream-output-pointer stream) (buffer-length buf))
144         (force-output stream)))
145     (b/v-replace buf thing
146                  :start1 (ssl-stream-output-pointer stream)
147                  :start2 start
148                  :end2 end)
149     (incf (ssl-stream-output-pointer stream) (- end start)))
150   thing)
151
152 (defmethod stream-finish-output ((stream ssl-stream))
153   (stream-force-output stream))
154
155 (defmethod stream-force-output ((stream ssl-stream))
156   (let ((buf (ssl-stream-output-buffer stream))
157         (fill-ptr (ssl-stream-output-pointer stream))
158         (handle (ssl-stream-handle stream)))
159     (when (plusp fill-ptr)
160       (unless handle
161         (error "output operation on closed SSL stream"))
162       (with-pointer-to-vector-data (ptr buf)
163         (ensure-ssl-funcall stream handle #'ssl-write handle ptr fill-ptr))
164       (setf (ssl-stream-output-pointer stream) 0))))
165
166 #+clozure-common-lisp
167 (defun install-nonblock-flag (fd)
168   (ccl::fd-set-flags fd (logior (ccl::fd-get-flags fd) #$O_NONBLOCK)))
169
170 #+(and sbcl (not win32))
171 (defun install-nonblock-flag (fd)
172   (sb-posix:fcntl fd
173                   sb-posix::f-setfl
174                   (logior (sb-posix:fcntl fd sb-posix::f-getfl)
175                           sb-posix::o-nonblock)))
176
177 #-(or clozure-common-lisp (and sbcl (not win32)))
178 (defun install-nonblock-flag (fd)
179   (declare (ignore fd)))
180
181
182 ;;; interface functions
183 ;;;
184
185 (defun install-handle-and-bio (stream handle socket unwrap-stream-p)
186   (setf (ssl-stream-handle stream) handle)
187   (when unwrap-stream-p
188     (let ((fd (stream-fd socket)))
189       (when fd
190         (setf socket fd))))
191   (etypecase socket
192     (integer
193      (install-nonblock-flag socket)
194      (ssl-set-fd handle socket))
195     (stream
196      (ssl-set-bio handle (bio-new-lisp) (bio-new-lisp))))
197   (ssl-ctx-ctrl handle
198                 +SSL_CTRL_MODE+
199                 +SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER+
200                 0)
201   socket)
202
203 (defun install-key-and-cert (handle key certificate)
204   (when key
205     (unless (eql 1 (ssl-use-rsa-privatekey-file handle
206                                                 key
207                                                 +ssl-filetype-pem+))
208       (error 'ssl-error-initialize :reason (format nil "Can't load RSA private key file ~A" key))))
209   (when certificate
210     (unless (eql 1 (ssl-use-certificate-file handle
211                                              certificate
212                                              +ssl-filetype-pem+))
213       (error 'ssl-error-initialize
214              :reason (format nil "Can't load certificate ~A" certificate)))))
215
216 (defun handle-external-format (stream ef)
217   (if ef
218       (flexi-streams:make-flexi-stream stream :external-format ef)
219       stream))
220
221 ;; fixme: free the context when errors happen in this function
222 (defun make-ssl-client-stream
223     (socket &key certificate key (method 'ssl-v23-method) external-format
224                  close-callback (unwrap-stream-p t))
225   "Returns an SSL stream for the client socket descriptor SOCKET.
226 CERTIFICATE is the path to a file containing the PEM-encoded certificate for
227  your client. KEY is the path to the PEM-encoded key for the client, which
228 must not be associated with a passphrase."
229   (ensure-initialized method)
230   (let ((stream (make-instance 'ssl-stream
231                                :socket socket
232                                :close-callback close-callback))
233         (handle (ssl-new *ssl-global-context*)))
234     (setf socket (install-handle-and-bio stream handle socket unwrap-stream-p))
235     (ssl-set-connect-state handle)
236     (install-key-and-cert handle key certificate)
237     (ensure-ssl-funcall stream handle #'ssl-connect handle)
238     (handle-external-format stream external-format)))
239
240 ;; fixme: free the context when errors happen in this function
241 (defun make-ssl-server-stream
242     (socket &key certificate key (method 'ssl-v23-method) external-format
243                  close-callback (unwrap-stream-p t))
244   "Returns an SSL stream for the server socket descriptor SOCKET.
245 CERTIFICATE is the path to a file containing the PEM-encoded certificate for
246  your server. KEY is the path to the PEM-encoded key for the server, which
247 must not be associated with a passphrase."
248   (ensure-initialized method)
249   (let ((stream (make-instance 'ssl-server-stream
250                  :socket socket
251                  :close-callback close-callback
252                  :certificate certificate
253                  :key key))
254         (handle (ssl-new *ssl-global-context*)))
255     (setf socket (install-handle-and-bio stream handle socket unwrap-stream-p))
256     (ssl-set-accept-state handle)
257     (when (zerop (ssl-set-cipher-list handle "ALL"))
258       (error 'ssl-error-initialize :reason "Can't set SSL cipher list"))
259     (install-key-and-cert handle key certificate)
260     (ensure-ssl-funcall stream handle #'ssl-accept handle)
261     (handle-external-format stream external-format)))
262
263 #+openmcl
264 (defmethod stream-deadline ((stream ccl::basic-stream))
265   (ccl::ioblock-deadline (ccl::stream-ioblock stream t)))
266 #+openmcl
267 (defmethod stream-deadline ((stream t))
268   nil)
269
270
271 (defgeneric stream-fd (stream))
272 (defmethod stream-fd (stream) stream)
273
274 #+sbcl
275 (defmethod stream-fd ((stream sb-sys:fd-stream))
276   (sb-sys:fd-stream-fd stream))
277
278 #+cmu
279 (defmethod stream-fd ((stream system:fd-stream))
280   (system:fd-stream-fd stream))
281
282 #+openmcl
283 (defmethod stream-fd ((stream ccl::basic-stream))
284   (ccl::ioblock-device (ccl::stream-ioblock stream t)))
285
286 #+clisp
287 (defmethod stream-fd ((stream stream))
288   ;; sockets appear to be direct instances of STREAM
289   (ignore-errors (socket:stream-handles stream)))
Note: See TracBrowser for help on using the browser.