Recently Written · git

clic

MIRROR ONLY Gopher client with pretty colours in Common Lisp

git clone https://github.com/equwal/clic

Log | Files | Refs


3rdparties/software/cl+ssl-20200427-git/src/ffi.lisp (37286 bytes)

1 ;;;; -*- Mode: LISP; Syntax: COMMON-LISP; indent-tabs-mode: nil; coding: utf-8; show-trailing-whitespace: t -*-
2 ;;;
3 ;;; Copyright (C) 2001, 2003  Eric Marsden
4 ;;; Copyright (C) 2005  David Lichteblau
5 ;;; "the conditions and ENSURE-SSL-FUNCALL are by Jochen Schmidt."
6 ;;;
7 ;;; See LICENSE for details.
8 
9 #+xcvb (module (:depends-on ("package" "conditions")))
10 
11 (eval-when (:compile-toplevel)
12   (declaim
13    (optimize (speed 3) (space 1) (safety 1) (debug 0) (compilation-speed 0))))
14 
15 (in-package :cl+ssl)
16 
17 ;;; Some lisps (CMUCL) fail when we try to define
18 ;;; a foreign function which is absent in the loaded
19 ;;; foreign library. CMUCL fails when the compiled .fasl
20 ;;; file is loaded, and the failure can not be
21 ;;; captured even by CL condition handlers, i.e.
22 ;;; wrapping (defcfun "removed-function" ...)
23 ;;; into (ignore-errors ...) doesn't help.
24 ;;;
25 ;;; See https://gitlab.common-lisp.net/cmucl/cmucl/issues/74
26 ;;;
27 ;;; As OpenSSL often changs API (removes / adds functions)
28 ;;; we need to solve this problem for CMUCL.
29 ;;;
30 ;;; We do this on CMUCL by calling functions which exists
31 ;;; not in all OpenSSL versions through a pointer
32 ;;; received with cffi:foreign-symbol-pointer.
33 ;;; So a lisp wrapper function for such foreign function
34 ;;; looks up a pointer to the required foreign function
35 ;;; in a hash table.
36 
37 (defparameter *late-bound-foreign-function-pointers*
38   (make-hash-table :test 'equal))
39 
40 (defmacro defcfun-late-bound (name-and-options &body body)
41   (assert (not (eq (alexandria:lastcar body)
42                    '&rest))
43           (body)
44           "The BODY format is implemented in a limited way
45 comparing to CFFI:DEFCFUN - we don't support the &REST which specifies vararg
46 functions. Feel free to implement the support if you have a use case.")
47   (assert (and (>= (length name-and-options) 2)
48                (stringp (first name-and-options))
49                (symbolp (second name-and-options)))
50           (name-and-options)
51           "Unsupported NAME-AND-OPTIONS format: ~S.
52 \(Of all the NAME-AND-OPTIONS variants allowed by CFFI:DEFCFUN we have only
53 implemented support for (FOREIGN-NAME LISP-NAME ...) where FOREIGN-NAME is a
54 STRING and LISP-NAME is a SYMBOL. Fell free to implement support the remaining
55 variants if you have use cases for them.)"
56           name-and-options)
57 
58   (let ((foreign-name-str (first name-and-options))
59         (lisp-name (second name-and-options))
60         (docstring (when (stringp (car body)) (pop body)))
61         (return-type (first body))
62         (arg-names (mapcar #'first (rest body)))
63         (arg-types (mapcar #'second (rest body)))
64         (library (getf (cddr name-and-options) :library))
65         (convention (getf (cddr name-and-options) :convention))
66         (ptr-var (gensym (string 'ptr))))
67     `(progn
68        (setf (gethash ,foreign-name-str *late-bound-foreign-function-pointers*)
69              (or (cffi:foreign-symbol-pointer ,foreign-name-str
70                                               ,@(when library `(:library ',library)))
71                  'foreign-symbol-not-found))
72        (defun ,lisp-name (,@arg-names)
73          ,@(when docstring (list docstring))
74          (let ((,ptr-var (gethash ,foreign-name-str *late-bound-foreign-function-pointers*)))
75            (when (null ,ptr-var)
76              (error "Unexpacted state, no value in *late-bound-foreign-function-pointers* for ~A"
77                     ,foreign-name-str))
78            (when (eq ,ptr-var 'foreign-symbol-not-found)
79              (error "The current version of OpenSSL libcrypto doesn't provide ~A"
80                     ,foreign-name-str))
81            (cffi:foreign-funcall-pointer ,ptr-var
82                                          ,(when convention (list convention))
83                                          ,@(mapcan #'list arg-types arg-names)
84                                          ,return-type))))))
85 
86 (defmacro defcfun-versioned ((&key since vanished) name-and-options &body body)
87   (if (and (or since vanished)
88            (member :cmucl *features*))
89       `(defcfun-late-bound ,name-and-options ,@body)
90       `(cffi:defcfun ,name-and-options ,@body)))
91 
92 
93 ;;; Code for checking that we got the correct foreign symbols right.
94 ;;; Implemented only for LispWorks for now.
95 (defvar *cl+ssl-ssl-foreign-function-names* nil)
96 (defvar *cl+ssl-crypto-foreign-function-names* nil)
97 
98 #+lispworks
99 (defun check-cl+ssl-symbols ()
100   (dolist (ssl-symbol *cl+ssl-ssl-foreign-function-names*)
101     (when (fli:null-pointer-p (fli:make-pointer :symbol-name ssl-symbol :module 'libssl :errorp nil))
102       (format *error-output* "Symbol ~s undefined~%" ssl-symbol)))
103   (dolist (crypto-symbol *cl+ssl-crypto-foreign-function-names*)
104     (when (fli:null-pointer-p (fli:make-pointer :symbol-name crypto-symbol :module 'libcrypto :errorp nil))
105       (format *error-output* "Symbol ~s undefined~%" crypto-symbol))))
106 
107 (defmacro define-ssl-function-ex ((&key since vanished) name-and-options &body body)
108   `(progn
109      ;; debugging
110      (pushnew  ,(car name-and-options)
111                *cl+ssl-ssl-foreign-function-names*
112                :test 'equal)
113      (defcfun-versioned (:since ,since :vanished ,vanished)
114          ,(append name-and-options '(:library libssl))
115        ,@body)))
116 
117 (defmacro define-ssl-function (name-and-options &body body)
118   `(define-ssl-function-ex () ,name-and-options ,@body))
119 
120 (defmacro define-crypto-function-ex ((&key since vanished) name-and-options &body body)
121   `(progn
122      ;; debugging
123      (pushnew ,(car name-and-options)
124               *cl+ssl-crypto-foreign-function-names*
125               :test 'equal)
126      (defcfun-versioned (:since ,since :vanished ,vanished)
127          ;; On Darwin, LispWorks has boringssl always loaded
128          ;; (https://github.com/cl-plus-ssl/cl-plus-ssl/issues/61),
129          ;; ABCL somehow has libressl loaded
130          ;; (https://github.com/cl-plus-ssl/cl-plus-ssl/pull/89),
131          ;; and when we load openssl and declare ffi functions
132          ;; without explicitly specifying the :library option,
133          ;; some foreign symbols are resolved as boringssl / libressl symbols,
134          ;; others are resolved as openssl functions.
135          ;; This mix results in failures, of course.
136          ;; We fix these two implementations by passing the :library option.
137          ;; Not for other implementations because this may be
138          ;; incompatible with :cl+ssl-foreign-libs-already-loaded
139          ;; but these two implementations just break without
140          ;; that, so it's better to possibly sacrify the
141          ;; :cl+ssl-foreign-libs-already-loaded (we haven't tested)
142          ;; than have them broken completely.
143          ;; TODO: extend the :cl+ssl-foreign-libs-already-loaded
144          ;; mechanism with possibility for user to specify value
145          ;; for the :library option.
146          ,(append name-and-options
147                   #+(and (or abcl lispworks) darwin) '(:library libcrypto))
148        ,@body)))
149 
150 (defmacro define-crypto-function (name-and-options &body body)
151   `(define-crypto-function-ex () ,name-and-options ,@body))
152 
153 
154 ;;; Global state
155 ;;;
156 (defvar *ssl-global-context* nil)
157 (defvar *ssl-global-method* nil)
158 (defvar *bio-lisp-method* nil)
159 
160 (defparameter *blockp* t)
161 (defparameter *partial-read-p* nil)
162 
163 (defun ssl-initialized-p ()
164   (and *ssl-global-context* *ssl-global-method*))
165 
166 
167 ;;; Constants
168 ;;;
169 (defconstant +ssl-filetype-pem+ 1)
170 (defconstant +ssl-filetype-asn1+ 2)
171 (defconstant +ssl-filetype-default+ 3)
172 
173 (defconstant +SSL-CTRL-OPTIONS+ 32)
174 (defconstant +SSL_CTRL_SET_SESS_CACHE_MODE+ 44)
175 (defconstant +SSL_CTRL_MODE+ 33)
176 
177 (defconstant +SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER+ 2)
178 
179 (defconstant +RSA_F4+ #x10001)
180 
181 (defconstant +SSL-SESS-CACHE-OFF+ #x0000
182   "No session caching for client or server takes place.")
183 (defconstant +SSL-SESS-CACHE-CLIENT+ #x0001
184   "Client sessions are added to the session cache.
185 As there is no reliable way for the OpenSSL library to know whether a session should be reused
186 or which session to choose (due to the abstract BIO layer the SSL engine does not have details
187 about the connection), the application must select the session to be reused by using the
188 SSL-SET-SESSION function. This option is not activated by default.")
189 (defconstant +SSL-SESS-CACHE-SERVER+ #x0002
190   "Server sessions are added to the session cache.
191 When a client proposes a session to be reused, the server looks for the corresponding session
192 in (first) the internal session cache (unless +SSL-SESS-CACHE-NO-INTERNAL-LOOKUP+ is set), then
193 (second) in the external cache if available. If the session is found, the server will try to
194 reuse the session. This is the default.")
195 (defconstant +SSL-SESS-CACHE-BOTH+ (logior +SSL-SESS-CACHE-CLIENT+ +SSL-SESS-CACHE-SERVER+)
196   "Enable both +SSL-SESS-CACHE-CLIENT+ and +SSL-SESS-CACHE-SERVER+ at the same time.")
197 (defconstant +SSL-SESS-CACHE-NO-AUTO-CLEAR+ #x0080
198   "Normally the session cache is checked for expired sessions every 255 connections using the
199 SSL-CTX-FLUSH-SESSIONS function. Since this may lead to a delay which cannot be controlled,
200 the automatic flushing may be disabled and SSL-CTX-FLUSH-SESSIONS can be called explicitly
201 by the application.")
202 (defconstant +SSL-SESS-CACHE-NO-INTERNAL-LOOKUP+ #x0100
203   "By setting this flag, session-resume operations in an SSL/TLS server will not automatically
204 look up sessions in the internal cache, even if sessions are automatically stored there.
205 If external session caching callbacks are in use, this flag guarantees that all lookups are
206 directed to the external cache. As automatic lookup only applies for SSL/TLS servers, the flag
207 has no effect on clients.")
208 (defconstant +SSL-SESS-CACHE-NO-INTERNAL-STORE+ #x0200
209   "Depending on the presence of +SSL-SESS-CACHE-CLIENT+ and/or +SSL-SESS-CACHE-SERVER+, sessions
210 negotiated in an SSL/TLS handshake may be cached for possible reuse. Normally a new session is
211 added to the internal cache as well as any external session caching (callback) that is configured
212 for the SSL-CTX. This flag will prevent sessions being stored in the internal cache (though the
213 application can add them manually using SSL-CTX-ADD-SESSION). Note: in any SSL/TLS servers where
214 external caching is configured, any successful session lookups in the external cache (ie. for
215 session-resume requests) would normally be copied into the local cache before processing continues
216 - this flag prevents these additions to the internal cache as well.")
217 (defconstant +SSL-SESS-CACHE-NO-INTERNAL+ (logior +SSL-SESS-CACHE-NO-INTERNAL-LOOKUP+ +SSL-SESS-CACHE-NO-INTERNAL-STORE+)
218   "Enable both +SSL-SESS-CACHE-NO-INTERNAL-LOOKUP+ and +SSL-SESS-CACHE-NO-INTERNAL-STORE+ at the same time.")
219 
220 (defconstant +SSL-VERIFY-NONE+ #x00)
221 (defconstant +SSL-VERIFY-PEER+ #x01)
222 (defconstant +SSL-VERIFY-FAIL-IF-NO-PEER-CERT+ #x02)
223 (defconstant +SSL-VERIFY-CLIENT-ONCE+ #x04)
224 
225 (defconstant +SSL-OP-ALL+ #x80000BFF)
226 
227 (defconstant +SSL-OP-NO-SSLv2+   #x01000000)
228 (defconstant +SSL-OP-NO-SSLv3+   #x02000000)
229 (defconstant +SSL-OP-NO-TLSv1+   #x04000000)
230 (defconstant +SSL-OP-NO-TLSv1-2+ #x08000000)
231 (defconstant +SSL-OP-NO-TLSv1-1+ #x10000000)
232 
233 (defvar *tmp-rsa-key-512* nil)
234 (defvar *tmp-rsa-key-1024* nil)
235 (defvar *tmp-rsa-key-2048* nil)
236 
237 ;;; Misc
238 ;;;
239 (defmacro while (cond &body body)
240   `(do () ((not ,cond)) ,@body))
241 
242 
243 ;;; Function definitions
244 ;;;
245 
246 (cffi:defcfun (#-windows "close" #+windows "closesocket" close-socket)
247     :int
248   (socket :int))
249 
250 (declaim (inline ssl-write ssl-read ssl-connect ssl-accept))
251 
252 (cffi:defctype ssl-method :pointer)
253 (cffi:defctype ssl-ctx :pointer)
254 (cffi:defctype ssl-pointer :pointer)
255 
256 
257 (define-crypto-function-ex (:vanished "1.1.0") ("SSLeay" ssl-eay)
258         :long)
259 
260 (define-crypto-function-ex (:since "1.1.0") ("OpenSSL_version_num" openssl-version-num)
261         :long)
262 
263 (defun compat-openssl-version ()
264   (or (ignore-errors (openssl-version-num))
265       (ignore-errors (ssl-eay))
266       (error "No OpenSSL version number could be determined, both SSLeay and OpenSSL_version_num failed.")))
267 
268 (defun encode-openssl-version (major minor &optional (patch 0) (prerelease))
269   "Builds a version number to compare OpenSSL against.
270 Note: the _really_ old formats (<= 0.9.4) are not supported."
271   (declare (type (integer 0 3) major)
272            (type (integer 0 10) minor)
273            (type (integer 0 20) patch))
274   (logior (ash major 28)
275           (ash minor 20)
276           (ash patch 4)
277           (if prerelease #xf #x0)))
278 
279 (defun openssl-is-at-least (major minor &optional (patch 0) (prerelease))
280   (>= (compat-openssl-version)
281       (encode-openssl-version major minor patch prerelease)))
282 
283 (defun openssl-is-not-even (major minor &optional (patch 0) (prerelease))
284   (< (compat-openssl-version)
285      (encode-openssl-version major minor patch prerelease)))
286 
287 (defun libresslp ()
288   ;; LibreSSL can be distinguished by
289   ;; OpenSSL_version_num() always returning 0x020000000,
290   ;; where 2 is the major version number.
291   ;; http://man.openbsd.org/OPENSSL_VERSION_NUMBER.3
292   ;; And OpenSSL will never use the major version 2:
293   ;; "This document outlines the design of OpenSSL 3.0, the next version of OpenSSL after 1.1.1"
294   ;; https://www.openssl.org/docs/OpenSSL300Design.html
295   (= #x20000000 (compat-openssl-version)))
296 
297 (define-ssl-function ("SSL_get_version" ssl-get-version)
298     :string
299   (ssl ssl-pointer))
300 (define-ssl-function-ex (:vanished "1.1.0") ("SSL_load_error_strings" ssl-load-error-strings)
301     :void)
302 (define-ssl-function-ex (:vanished "1.1.0") ("SSL_library_init" ssl-library-init)
303     :int)
304 ;;
305 ;; We don't refer SSLv2_client_method as the default
306 ;; builds of OpenSSL do not have it, due to insecurity
307 ;; of the SSL v2 protocol (see https://www.openssl.org/docs/ssl/SSL_CTX_new.html
308 ;; and https://github.com/cl-plus-ssl/cl-plus-ssl/issues/6)
309 ;;
310 ;; (define-ssl-function ("SSLv2_client_method" ssl-v2-client-method)
311 ;;     ssl-method)
312 (define-ssl-function-ex (:vanished "1.1.0") ("SSLv23_client_method" ssl-v23-client-method)
313     ssl-method)
314 (define-ssl-function-ex (:vanished "1.1.0") ("SSLv23_server_method" ssl-v23-server-method)
315     ssl-method)
316 (define-ssl-function-ex (:vanished "1.1.0") ("SSLv23_method" ssl-v23-method)
317     ssl-method)
318 (define-ssl-function-ex (:vanished "1.1.0") ("SSLv3_client_method" ssl-v3-client-method)
319     ssl-method)
320 (define-ssl-function-ex (:vanished "1.1.0") ("SSLv3_server_method" ssl-v3-server-method)
321     ssl-method)
322 (define-ssl-function-ex (:vanished "1.1.0") ("SSLv3_method" ssl-v3-method)
323     ssl-method)
324 (define-ssl-function ("TLSv1_client_method" ssl-TLSv1-client-method)
325     ssl-method)
326 (define-ssl-function ("TLSv1_server_method" ssl-TLSv1-server-method)
327     ssl-method)
328 (define-ssl-function ("TLSv1_method" ssl-TLSv1-method)
329     ssl-method)
330 (define-ssl-function-ex (:since "1.0.2") ("TLSv1_1_client_method" ssl-TLSv1-1-client-method)
331     ssl-method)
332 (define-ssl-function-ex (:since "1.0.2") ("TLSv1_1_server_method" ssl-TLSv1-1-server-method)
333     ssl-method)
334 (define-ssl-function-ex (:since "1.0.2") ("TLSv1_1_method" ssl-TLSv1-1-method)
335     ssl-method)
336 (define-ssl-function-ex (:since "1.0.2") ("TLSv1_2_client_method" ssl-TLSv1-2-client-method)
337     ssl-method)
338 (define-ssl-function-ex (:since "1.0.2") ("TLSv1_2_server_method" ssl-TLSv1-2-server-method)
339     ssl-method)
340 (define-ssl-function-ex (:since "1.0.2") ("TLSv1_2_method" ssl-TLSv1-2-method)
341     ssl-method)
342 (define-ssl-function-ex (:since "1.1.0") ("TLS_method" tls-method)
343     ssl-method)
344 
345 (define-ssl-function ("SSL_CTX_new" ssl-ctx-new)
346     ssl-ctx
347   (method ssl-method))
348 (define-ssl-function ("SSL_new" ssl-new)
349     ssl-pointer
350   (ctx ssl-ctx))
351 (define-ssl-function ("SSL_get_fd" ssl-get-fd)
352     :int
353   (ssl ssl-pointer))
354 (define-ssl-function ("SSL_set_fd" ssl-set-fd)
355     :int
356   (ssl ssl-pointer)
357   (fd :int))
358 (define-ssl-function ("SSL_set_bio" ssl-set-bio)
359     :void
360   (ssl ssl-pointer)
361   (rbio :pointer)
362   (wbio :pointer))
363 (define-ssl-function ("SSL_get_error" ssl-get-error)
364     :int
365   (ssl ssl-pointer)
366   (ret :int))
367 (define-ssl-function ("SSL_set_connect_state" ssl-set-connect-state)
368     :void
369   (ssl ssl-pointer))
370 (define-ssl-function ("SSL_set_accept_state" ssl-set-accept-state)
371     :void
372   (ssl ssl-pointer))
373 (define-ssl-function ("SSL_connect" ssl-connect)
374     :int
375   (ssl ssl-pointer))
376 (define-ssl-function ("SSL_accept" ssl-accept)
377     :int
378   (ssl ssl-pointer))
379 (define-ssl-function ("SSL_write" ssl-write)
380     :int
381   (ssl ssl-pointer)
382   (buf :pointer)
383   (num :int))
384 (define-ssl-function ("SSL_read" ssl-read)
385     :int
386   (ssl ssl-pointer)
387   (buf :pointer)
388   (num :int))
389 (define-ssl-function ("SSL_shutdown" ssl-shutdown)
390     :void
391   (ssl ssl-pointer))
392 (define-ssl-function ("SSL_free" ssl-free)
393     :void
394   (ssl ssl-pointer))
395 (define-ssl-function ("SSL_CTX_free" ssl-ctx-free)
396     :void
397   (ctx ssl-ctx))
398 (define-crypto-function ("BIO_ctrl" bio-set-fd)
399     :long
400   (bio :pointer)
401   (cmd :int)
402   (larg :long)
403   (parg :pointer))
404 (define-crypto-function ("BIO_new_socket" bio-new-socket)
405     :pointer
406   (fd :int)
407   (close-flag :int))
408 (define-crypto-function ("BIO_new" bio-new)
409     :pointer
410   (method :pointer))
411 
412 (define-crypto-function ("ERR_get_error" err-get-error)
413     :unsigned-long)
414 (define-crypto-function ("ERR_error_string" err-error-string)
415     :string
416   (e :unsigned-long)
417   (buf :pointer))
418 
419 (define-ssl-function ("SSL_set_cipher_list" ssl-set-cipher-list)
420     :int
421   (ssl ssl-pointer)
422   (str :string))
423 (define-ssl-function ("SSL_use_RSAPrivateKey_file" ssl-use-rsa-privatekey-file)
424     :int
425   (ssl ssl-pointer)
426   (str :string)
427   ;; either +ssl-filetype-pem+ or +ssl-filetype-asn1+
428   (type :int))
429 (define-ssl-function
430     ("SSL_CTX_use_RSAPrivateKey_file" ssl-ctx-use-rsa-privatekey-file)
431     :int
432   (ctx ssl-ctx)
433   (type :int))
434 (define-ssl-function ("SSL_use_PrivateKey_file" ssl-use-privatekey-file)
435   :int
436   (ssl ssl-pointer)
437   (str :string)
438   ;; either +ssl-filetype-pem+ or +ssl-filetype-asn1+
439   (type :int))
440 (define-ssl-function
441     ("SSL_CTX_use_PrivateKey_file" ssl-ctx-use-privatekey-file)
442   :int
443   (ctx ssl-ctx)
444   (type :int))
445 (define-ssl-function ("SSL_use_certificate_file" ssl-use-certificate-file)
446     :int
447   (ssl ssl-pointer)
448   (str :string)
449   (type :int))
450 #+new-openssl
451 (define-ssl-function ("SSL_CTX_set_options" ssl-ctx-set-options)
452                  :long
453                (ctx :pointer)
454                (options :long))
455 #-new-openssl
456 (defun ssl-ctx-set-options (ctx options)
457   (ssl-ctx-ctrl ctx +SSL-CTRL-OPTIONS+ options (cffi:null-pointer)))
458 (define-ssl-function ("SSL_CTX_set_cipher_list" ssl-ctx-set-cipher-list%)
459     :int
460   (ctx :pointer)
461   (ciphers :pointer))
462 (defun ssl-ctx-set-cipher-list (ctx ciphers)
463   (cffi:with-foreign-string (ciphers* ciphers)
464     (when (= 0 (ssl-ctx-set-cipher-list% ctx ciphers*))
465       (error 'ssl-error-initialize :reason "Can't set SSL cipher list" :queue (read-ssl-error-queue)))))
466 (define-ssl-function ("SSL_CTX_use_certificate_chain_file" ssl-ctx-use-certificate-chain-file)
467     :int
468   (ctx ssl-ctx)
469   (str :string))
470 (define-ssl-function ("SSL_CTX_load_verify_locations" ssl-ctx-load-verify-locations)
471     :int
472   (ctx ssl-ctx)
473   (CAfile :string)
474   (CApath :string))
475 (define-ssl-function ("SSL_CTX_set_client_CA_list" ssl-ctx-set-client-ca-list)
476     :void
477   (ctx ssl-ctx)
478   (list ssl-pointer))
479 (define-ssl-function ("SSL_load_client_CA_file" ssl-load-client-ca-file)
480     ssl-pointer
481   (file :string))
482 
483 (define-ssl-function ("SSL_CTX_ctrl" ssl-ctx-ctrl)
484     :long
485   (ctx ssl-ctx)
486   (cmd :int)
487   ;; Despite declared as long in the original OpenSSL headers,
488   ;; passing to larg for example 2181041151 which is the result of
489   ;;     (logior cl+ssl::+SSL-OP-ALL+
490   ;;             cl+ssl::+SSL-OP-NO-SSLv2+
491   ;;             cl+ssl::+SSL-OP-NO-SSLv3+)
492   ;; causes CFFI on 32 bit platforms to signal an error
493   ;; "The value 2181041151 is not of the expected type (SIGNED-BYTE 32)"
494   ;; The problem is that 2181041151 requires 32 bits by itself and
495   ;; there is no place left for the sign bit.
496   ;; In C the compiler silently coerces unsigned to signed,
497   ;; but CFFI raises this error.
498   ;; Therefore we use :UNSIGNED-LONG for LARG.
499   (larg :unsigned-long)
500   (parg :pointer))
501 
502 (define-ssl-function ("SSL_ctrl" ssl-ctrl)
503     :long
504   (ssl :pointer)
505   (cmd :int)
506   (larg :long)
507   (parg :pointer))
508 
509 (define-ssl-function ("SSL_CTX_set_default_passwd_cb" ssl-ctx-set-default-passwd-cb)
510     :void
511   (ctx ssl-ctx)
512   (pem_passwd_cb :pointer))
513 
514 (define-crypto-function-ex (:vanished "1.1.0") ("CRYPTO_num_locks" crypto-num-locks) :int)
515 (define-crypto-function-ex (:vanished "1.1.0") ("CRYPTO_set_locking_callback" crypto-set-locking-callback)
516     :void
517   (fun :pointer))
518 (define-crypto-function-ex (:vanished "1.1.0") ("CRYPTO_set_id_callback" crypto-set-id-callback)
519     :void
520   (fun :pointer))
521 
522 (define-crypto-function ("RAND_seed" rand-seed)
523     :void
524   (buf :pointer)
525   (num :int))
526 (define-crypto-function ("RAND_bytes" rand-bytes)
527     :int
528   (buf :pointer)
529   (num :int))
530 
531 (define-ssl-function ("SSL_CTX_set_verify_depth" ssl-ctx-set-verify-depth)
532     :void
533   (ctx :pointer)
534   (depth :int))
535 
536 (define-ssl-function ("SSL_CTX_set_verify" ssl-ctx-set-verify)
537     :void
538   (ctx :pointer)
539   (mode :int)
540   (verify-callback :pointer))
541 
542 (define-ssl-function ("SSL_get_verify_result" ssl-get-verify-result)
543     :long
544   (ssl ssl-pointer))
545 
546 (define-ssl-function ("SSL_get_peer_certificate" ssl-get-peer-certificate)
547     :pointer
548   (ssl ssl-pointer))
549 
550 ;;; X509 & ASN1
551 (define-crypto-function ("X509_free" x509-free)
552     :void
553   (x509 :pointer))
554 
555 (define-crypto-function ("X509_NAME_oneline" x509-name-oneline)
556     :pointer
557   (x509-name :pointer)
558   (buf :pointer)
559   (size :int))
560 
561 (define-crypto-function ("X509_NAME_get_index_by_NID" x509-name-get-index-by-nid)
562     :int
563   (name :pointer)
564   (nid :int)
565   (lastpos :int))
566 
567 (define-crypto-function ("X509_NAME_get_entry" x509-name-get-entry)
568     :pointer
569   (name :pointer)
570   (log :int))
571 
572 (define-crypto-function ("X509_NAME_ENTRY_get_data" x509-name-entry-get-data)
573     :pointer
574   (name-entry :pointer))
575 
576 (define-crypto-function ("X509_get_issuer_name" x509-get-issuer-name)
577     :pointer                            ; *X509_NAME
578   (x509 :pointer))
579 
580 (define-crypto-function ("X509_get_subject_name" x509-get-subject-name)
581     :pointer                            ; *X509_NAME
582   (x509 :pointer))
583 
584 (define-crypto-function ("X509_get_ext_d2i" x509-get-ext-d2i)
585     :pointer
586   (cert :pointer)
587   (nid :int)
588   (crit :pointer)
589   (idx :pointer))
590 
591 (define-crypto-function ("X509_STORE_CTX_get_error" x509-store-ctx-get-error)
592     :int
593   (ctx :pointer))
594 
595 (define-crypto-function ("d2i_X509" d2i-x509)
596     :pointer
597   (*px :pointer)
598   (in :pointer)
599   (len :int))
600 
601 ;; GENERAL-NAME types
602 (defconstant +GEN-OTHERNAME+  0)
603 (defconstant +GEN-EMAIL+  1)
604 (defconstant +GEN-DNS+    2)
605 (defconstant +GEN-X400+ 3)
606 (defconstant +GEN-DIRNAME+  4)
607 (defconstant +GEN-EDIPARTY+ 5)
608 (defconstant +GEN-URI+    6)
609 (defconstant +GEN-IPADD+  7)
610 (defconstant +GEN-RID+    8)
611 
612 (defconstant +v-asn1-octet-string+ 4)
613 (defconstant +v-asn1-utf8string+ 12)
614 (defconstant +v-asn1-printablestring+ 19)
615 (defconstant +v-asn1-teletexstring+ 20)
616 (defconstant +v-asn1-iastring+ 22)
617 (defconstant +v-asn1-universalstring+ 28)
618 (defconstant +v-asn1-bmpstring+ 30)
619 
620 
621 (defconstant +NID-subject-alt-name+ 85)
622 (defconstant +NID-commonName+   13)
623 
624 (cffi:defcstruct general-name
625   (type :int)
626   (data :pointer))
627 
628 (define-crypto-function-ex (:vanished "1.1.0") ("sk_value" sk-value)
629     :pointer
630   (stack :pointer)
631   (index :int))
632 
633 (define-crypto-function-ex (:vanished "1.1.0") ("sk_num" sk-num)
634     :int
635   (stack :pointer))
636 
637 (define-crypto-function-ex (:since "1.1.0") ("OPENSSL_sk_value" openssl-sk-value)
638     :pointer
639   (stack :pointer)
640   (index :int))
641 
642 (define-crypto-function-ex (:since "1.1.0") ("OPENSSL_sk_num" openssl-sk-num)
643     :int
644   (stack :pointer))
645 
646 (declaim (ftype (function (cffi:foreign-pointer fixnum) cffi:foreign-pointer) sk-general-name-value))
647 (defun sk-general-name-value (names index)
648   (if (and (not (libresslp))
649            (openssl-is-at-least 1 1))
650       (openssl-sk-value names index)
651       (sk-value names index)))
652 
653 (declaim (ftype (function (cffi:foreign-pointer) fixnum) sk-general-name-num))
654 (defun sk-general-name-num (names)
655   (if (and (not (libresslp))
656            (openssl-is-at-least 1 1))
657       (openssl-sk-num names)
658       (sk-num names)))
659 
660 (define-crypto-function ("GENERAL_NAMES_free" general-names-free)
661     :void
662   (general-names :pointer))
663 
664 (define-crypto-function ("ASN1_STRING_data" asn1-string-data)
665     :pointer
666   (asn1-string :pointer))
667 
668 (define-crypto-function ("ASN1_STRING_length" asn1-string-length)
669     :int
670   (asn1-string :pointer))
671 
672 (define-crypto-function ("ASN1_STRING_type" asn1-string-type)
673     :int
674   (asn1-string :pointer))
675 
676 (cffi:defcstruct asn1_string_st
677   (length :int)
678   (type :int)
679   (data :pointer)
680   (flags :long))
681 
682 ;; X509 & ASN1 - end
683 
684 (define-ssl-function ("SSL_CTX_set_default_verify_paths" ssl-ctx-set-default-verify-paths)
685     :int
686   (ctx :pointer))
687 
688 (define-ssl-function-ex (:since "1.1.0") ("SSL_CTX_set_default_verify_dir" ssl-ctx-set-default-verify-dir)
689     :int
690   (ctx :pointer))
691 
692 (define-ssl-function-ex (:since "1.1.0") ("SSL_CTX_set_default_verify_file" ssl-ctx-set-default-verify-file)
693     :int
694   (ctx :pointer))
695 
696 (define-crypto-function ("RSA_generate_key" rsa-generate-key)
697     :pointer
698   (num :int)
699   (e :unsigned-long)
700   (callback :pointer)
701   (opt :pointer))
702 
703 (define-crypto-function ("RSA_free" rsa-free)
704     :void
705   (rsa :pointer))
706 
707 (define-ssl-function-ex (:vanished "1.1.0") ("SSL_CTX_set_tmp_rsa_callback" ssl-ctx-set-tmp-rsa-callback)
708     :pointer
709   (ctx :pointer)
710   (callback :pointer))
711 
712 (cffi:defcallback tmp-rsa-callback :pointer ((ssl :pointer) (export-p :int) (key-length :int))
713   (declare (ignore ssl export-p))
714   (flet ((rsa-key (length)
715            (rsa-generate-key length
716                              +RSA_F4+
717                              (cffi:null-pointer)
718                              (cffi:null-pointer))))
719     (cond ((= key-length 512)
720            (unless *tmp-rsa-key-512*
721              (setf *tmp-rsa-key-512* (rsa-key key-length)))
722            *tmp-rsa-key-512*)
723           ((= key-length 1024)
724            (unless *tmp-rsa-key-1024*
725              (setf *tmp-rsa-key-1024* (rsa-key key-length)))
726            *tmp-rsa-key-1024*)
727           (t
728            (unless *tmp-rsa-key-2048*
729              (setf *tmp-rsa-key-2048* (rsa-key key-length)))
730            *tmp-rsa-key-2048*))))
731 
732 ;;; Funcall wrapper
733 ;;;
734 (defvar *socket*)
735 
736 (declaim (inline ensure-ssl-funcall))
737 (defun ensure-ssl-funcall (stream handle func &rest args)
738   (loop
739      (let ((nbytes
740       (let ((*socket* (ssl-stream-socket stream))) ;for Lisp-BIO callbacks
741         (apply func args))))
742        (when (plusp nbytes)
743    (return nbytes))
744        (let ((error (ssl-get-error handle nbytes)))
745    (case error
746      (#.+ssl-error-want-read+
747       (input-wait stream
748       (ssl-get-fd handle)
749       (ssl-stream-deadline stream)))
750      (#.+ssl-error-want-write+
751       (output-wait stream
752        (ssl-get-fd handle)
753        (ssl-stream-deadline stream)))
754      (t
755       (ssl-signal-error handle func error nbytes)))))))
756 
757 (declaim (inline nonblocking-ssl-funcall))
758 (defun nonblocking-ssl-funcall (stream handle func &rest args)
759   (loop
760      (let ((nbytes
761       (let ((*socket* (ssl-stream-socket stream))) ;for Lisp-BIO callbacks
762         (apply func args))))
763        (when (plusp nbytes)
764    (return nbytes))
765        (let ((error (ssl-get-error handle nbytes)))
766    (case error
767      ((#.+ssl-error-want-read+ #.+ssl-error-want-write+)
768       (return nbytes))
769      (t
770       (ssl-signal-error handle func error nbytes)))))))
771 
772 
773 ;;; Waiting for output to be possible
774 
775 #+clozure-common-lisp
776 (defun milliseconds-until-deadline (deadline stream)
777   (let* ((now (get-internal-real-time)))
778     (if (> now deadline)
779   (error 'ccl::communication-deadline-expired :stream stream)
780   (values
781    (round (- deadline now) (/ internal-time-units-per-second 1000))))))
782 
783 #+clozure-common-lisp
784 (defun output-wait (stream fd deadline)
785   (unless deadline
786     (setf deadline (stream-deadline (ssl-stream-socket stream))))
787   (let* ((timeout
788     (if deadline
789         (milliseconds-until-deadline deadline stream)
790         nil)))
791     (multiple-value-bind (win timedout error)
792   (ccl::process-output-wait fd timeout)
793       (unless win
794   (if timedout
795       (error 'ccl::communication-deadline-expired :stream stream)
796       (ccl::stream-io-error stream (- error) "write"))))))
797 
798 #+sbcl
799 (defun output-wait (stream fd deadline)
800   (declare (ignore stream))
801   (let ((timeout
802    ;; *deadline* is handled by wait-until-fd-usable automatically,
803    ;; but we need to turn a user-specified deadline into a timeout
804    (when deadline
805      (/ (- deadline (get-internal-real-time))
806         internal-time-units-per-second))))
807     (sb-sys:wait-until-fd-usable fd :output timeout)))
808 
809 #-(or clozure-common-lisp sbcl)
810 (defun output-wait (stream fd deadline)
811   (declare (ignore stream fd deadline))
812   ;; This situation means that the lisp set our fd to non-blocking mode,
813   ;; and streams.lisp didn't know how to undo that.
814   (warn "non-blocking stream encountered unexpectedly"))
815 
816 
817 ;;; Waiting for input to be possible
818 
819 #+clozure-common-lisp
820 (defun input-wait (stream fd deadline)
821   (unless deadline
822     (setf deadline (stream-deadline (ssl-stream-socket stream))))
823   (let* ((timeout
824     (if deadline
825         (milliseconds-until-deadline deadline stream)
826         nil)))
827     (multiple-value-bind (win timedout error)
828   (ccl::process-input-wait fd timeout)
829       (unless win
830   (if timedout
831       (error 'ccl::communication-deadline-expired :stream stream)
832       (ccl::stream-io-error stream (- error) "read"))))))
833 
834 #+sbcl
835 (defun input-wait (stream fd deadline)
836   (declare (ignore stream))
837   (let ((timeout
838    ;; *deadline* is handled by wait-until-fd-usable automatically,
839    ;; but we need to turn a user-specified deadline into a timeout
840    (when deadline
841      (/ (- deadline (get-internal-real-time))
842         internal-time-units-per-second))))
843     (sb-sys:wait-until-fd-usable fd :input timeout)))
844 
845 #-(or clozure-common-lisp sbcl)
846 (defun input-wait (stream fd deadline)
847   (declare (ignore stream fd deadline))
848   ;; This situation means that the lisp set our fd to non-blocking mode,
849   ;; and streams.lisp didn't know how to undo that.
850   (warn "non-blocking stream encountered unexpectedly"))
851 
852 
853 ;;; Encrypted PEM files support
854 ;;;
855 
856 ;; based on http://www.openssl.org/docs/ssl/SSL_CTX_set_default_passwd_cb.html
857 
858 (defvar *pem-password* ""
859   "The callback registered with SSL_CTX_set_default_passwd_cb
860 will use this value.")
861 
862 ;; The callback itself
863 (cffi:defcallback pem-password-callback :int
864     ((buf :pointer) (size :int) (rwflag :int) (unused :pointer))
865   (declare (ignore rwflag unused))
866   (let* ((password-str (coerce *pem-password* 'base-string))
867          (tmp (cffi:foreign-string-alloc password-str)))
868     (cffi:foreign-funcall "strncpy"
869                           :pointer buf
870                           :pointer tmp
871                           :int size)
872     (cffi:foreign-string-free tmp)
873     (setf (cffi:mem-ref buf :char (1- size)) 0)
874     (cffi:foreign-funcall "strlen" :pointer buf :int)))
875 
876 ;; The macro to be used by other code to provide password
877 ;; when loading PEM file.
878 (defmacro with-pem-password ((password) &body body)
879   `(let ((*pem-password* (or ,password "")))
880          ,@body))
881 
882 
883 ;;; Initialization
884 ;;;
885 
886 (defun init-prng (seed-byte-sequence)
887   (let* ((length (length seed-byte-sequence))
888          (buf (cffi:make-shareable-byte-vector length)))
889     (dotimes (i length)
890       (setf (elt buf i) (elt seed-byte-sequence i)))
891     (cffi:with-pointer-to-vector-data (ptr buf)
892       (rand-seed ptr length))))
893 
894 (defun ssl-ctx-set-session-cache-mode (ctx mode)
895   (ssl-ctx-ctrl ctx +SSL_CTRL_SET_SESS_CACHE_MODE+ mode (cffi:null-pointer)))
896 
897 (defun ssl-set-tlsext-host-name (ctx hostname)
898   (ssl-ctrl ctx 55 #|SSL_CTRL_SET_TLSEXT_HOSTNAME|# 0 #|TLSEXT_NAMETYPE_host_name|# hostname))
899 
900 (defvar *locks*)
901 (defconstant +CRYPTO-LOCK+ 1)
902 (defconstant +CRYPTO-UNLOCK+ 2)
903 (defconstant +CRYPTO-READ+ 4)
904 (defconstant +CRYPTO-WRITE+ 8)
905 
906 ;; zzz as of early 2011, bxthreads is totally broken on SBCL wrt. explicit
907 ;; locking of recursive locks.  with-recursive-lock works, but acquire/release
908 ;; don't.  Hence we use non-recursize locks here (but can use a recursive
909 ;; lock for the global lock).
910 
911 (cffi:defcallback locking-callback :void
912     ((mode :int)
913      (n :int)
914      (file :pointer) ;; could be (file :string), but we don't use FILE, so avoid the conversion
915      (line :int))
916   (declare (ignore file line))
917   ;; (assert (logtest mode (logior +CRYPTO-READ+ +CRYPTO-WRITE+)))
918   (let ((lock (elt *locks* n)))
919     (cond
920       ((logtest mode +CRYPTO-LOCK+)
921        (bt:acquire-lock lock))
922       ((logtest mode +CRYPTO-UNLOCK+)
923        (bt:release-lock lock))
924       (t
925        (error "fell through")))))
926 
927 (defvar *threads* (trivial-garbage:make-weak-hash-table :weakness :key))
928 (defvar *thread-counter* 0)
929 
930 (defparameter *global-lock*
931   (bordeaux-threads:make-recursive-lock "SSL initialization"))
932 
933 ;; zzz BUG: On a 32-bit system and under non-trivial load, this counter
934 ;; is likely to wrap in less than a year.
935 (cffi:defcallback threadid-callback :unsigned-long ()
936   (bordeaux-threads:with-recursive-lock-held (*global-lock*)
937     (let ((self (bt:current-thread)))
938       (or (gethash self *threads*)
939     (setf (gethash self *threads*)
940     (incf *thread-counter*))))))
941 
942 (defvar *ssl-check-verify-p* :unspecified
943   "DEPRECATED.
944 Use the (MAKE-SSL-CLIENT-STREAM .. :VERIFY ?) to enable/disable verification.
945 MAKE-CONTEXT also allows to enab/disable verification.")
946 
947 (defun default-ssl-method ()
948   (if (openssl-is-at-least 1 1)
949       'tls-method
950       'ssl-v23-method))
951 
952 (defun initialize (&key method rand-seed)
953   (when (or (openssl-is-not-even 1 1)
954             ;; Old versions of LibreSSL
955             ;; require this initialization
956             ;; (https://github.com/cl-plus-ssl/cl-plus-ssl/pull/91),
957             ;; new versions keep this API backwards
958             ;; compatible so we can call it too.
959             (libresslp))
960     (setf *locks* (loop
961                      repeat (crypto-num-locks)
962                      collect (bt:make-lock)))
963     (crypto-set-locking-callback (cffi:callback locking-callback))
964     (crypto-set-id-callback (cffi:callback threadid-callback))
965     (ssl-load-error-strings)
966     (ssl-library-init))
967   (setf *bio-lisp-method* (make-bio-lisp-method))
968   (when rand-seed
969     (init-prng rand-seed))
970   (setf *ssl-check-verify-p* :unspecified)
971   (setf *ssl-global-method* (funcall (or method (default-ssl-method))))
972   (setf *ssl-global-context* (ssl-ctx-new *ssl-global-method*))
973   (unless (eql 1 (ssl-ctx-set-default-verify-paths *ssl-global-context*))
974     (error "ssl-ctx-set-default-verify-paths failed."))
975   (ssl-ctx-set-session-cache-mode *ssl-global-context* 3)
976   (ssl-ctx-set-default-passwd-cb *ssl-global-context*
977                                  (cffi:callback pem-password-callback))
978   (when (or (openssl-is-not-even 1 1)
979             ;; Again, even if newer LibreSSL
980             ;; don't need this call, they keep
981             ;; the API compatibility so we can continue
982             ;; making this call.
983             (libresslp))
984     (ssl-ctx-set-tmp-rsa-callback *ssl-global-context*
985                                   (cffi:callback tmp-rsa-callback))))
986 
987 (defun ensure-initialized (&key method (rand-seed nil))
988   "In most cases you do *not* need to call this function, because it
989 is called automatically by all other functions. The only reason to
990 call it explicitly is to supply the RAND-SEED parameter. In this case
991 do it before calling any other functions.
992 
993 Just leave the default value for the METHOD parameter.
994 
995 RAND-SEED is an octet sequence to initialize OpenSSL random number generator.
996 On many platforms, including Linux and Windows, it may be leaved NIL (default),
997 because OpenSSL initializes the random number generator from OS specific service.
998 But for example on Solaris it may be necessary to supply this value.
999 The minimum length required by OpenSSL is 128 bits.
1000 See ttp://www.openssl.org/support/faq.html#USER1 for details.
1001 
1002 Hint: do not use Common Lisp RANDOM function to generate the RAND-SEED,
1003 because the function usually returns predictable values."
1004   #+lispworks
1005   (check-cl+ssl-symbols)
1006   (bordeaux-threads:with-recursive-lock-held (*global-lock*)
1007     (unless (ssl-initialized-p)
1008       (initialize :method method :rand-seed rand-seed))
1009     (unless *bio-lisp-method*
1010       (setf *bio-lisp-method* (make-bio-lisp-method)))))
1011 
1012 (defun use-certificate-chain-file (certificate-chain-file)
1013   "Loads a PEM encoded certificate chain file CERTIFICATE-CHAIN-FILE
1014 and adds the chain to global context. The certificates must be sorted
1015 starting with the subject's certificate (actual client or server certificate),
1016 followed by intermediate CA certificates if applicable, and ending at
1017 the highest level (root) CA. Note: the RELOAD function clears the global
1018 context and in particular the loaded certificate chain."
1019   (ensure-initialized)
1020   (ssl-ctx-use-certificate-chain-file *ssl-global-context* certificate-chain-file))
1021 
1022 (defun reload ()
1023   (if *ssl-global-context*
1024       (ssl-ctx-free *ssl-global-context*))
1025   (unless (member :cl+ssl-foreign-libs-already-loaded
1026                   *features*)
1027     (cffi:use-foreign-library libcrypto)
1028     (cffi:load-foreign-library 'libssl))
1029   (setf *ssl-global-context* nil)
1030   (setf *ssl-global-method* nil)
1031   (setf *tmp-rsa-key-512* nil)
1032   (setf *tmp-rsa-key-1024* nil))