This patch does the following:

* Removes EOL whitespace from a few lines.

* Implements get-peer-certificate and get-verify-result generic
  functions for ssl-stream instances.

  At the moment, get-peer-certificate returns an x509-certificate
  structure containing all subject and issuer names found in the peer
  certificate (see x509.lisp).  Unhandled string encodings yield
  tagged lists of bytes by default.

* Adds dependency on cffi-grovel (I used the version included with
  cffi 0.10.0).  cffi 0.10.0 may be required anyway due to use of its
  string decoding function supporting utf-8.  A large number of
  pertinent constants from the OpenSSL library are grovelled (see
  grovel.lisp), and keywords corresponding to them are used where
  constants defined in lisp had been used previously.

* Tweaks several cffi-defined functions and structs to accept and
  return keywords from the appropriate grovelled enumerations.

* Makes SSL cipher suite a user-configurable parameter with a
  reasonable default (see *cipher-list* in streams.lisp), and
  configures the OpenSSL context to use that suite for both client and
  server sockets.

* Makes trusted CA certificate store paths user-configurable
  parameters (see *trusted-ca-file* and *trusted-ca-directory* in
  ffi.lisp).  ssl-ctx-load-verify-locations is now called during
  initialization.

  Setting *trusted-ca-file* to a pathname or *trusted-ca-directory* to
  a directory name before initializing causes OpenSSL to consult the
  certificates found therein as trusted root certificates during
  verification.

  Certificates stored in *trusted-ca-directory* should be named (or
  linked to) according to the subject hash (e.g., ln -s certname.pem
  `openssl x509 -noout -hash -in certname.pem`.n (n >= 0)).

* Causes numeric error codes to be retained when processing library
  errors (see conditions.lisp).  Also recognizes WANT_ACCEPT error
  code.

* Probably introduces a noobish error or two.


        - Mike Watters <mike-cl@mwatters.net>


Note: I have only tested client mode and only under SBCL.

Sample output log for sbcl 1.0.18, cffi 0.10.0, and openssl 0.9.8e
(after loading usocket and cl+ssl):

CL-USER> (defun get-stream (address)
           (let ((s (usocket:socket-stream
                     (usocket:socket-connect
                      address 443 :element-type '(unsigned-byte 8)))))
             (cl+ssl:make-ssl-client-stream
              (cl+ssl:stream-fd s) :close-callback #'(lambda () (close s)))))
GET-STREAM
CL-USER> (get-stream "www.entrust.net")
WARNING: Neither path nor directory specified for CA root certificate store
#<CL+SSL::SSL-STREAM for 5>
CL-USER> (cl+ssl:get-verify-result *)
:UNABLE-TO-GET-ISSUER-CERT-LOCALLY
CL-USER> (cl+ssl:get-peer-certificate **)
#S(CL+SSL:X509-CERTIFICATE
   :SUBJECT ((:COMMON-NAME "www.entrust.net") (:SERIAL-NUMBER "D04566428")
             (:ORGANIZATIONAL-UNIT-NAME "Entrust Certificate Services")
             (:ORGANIZATION-NAME "Entrust Inc.")
             (:UNDEF "US" "Maryland" "V1.0, Clause 5.(b)")
             (:LOCALITY-NAME "Ottawa") (:STATE-OR-PROVINCE-NAME "Ontario")
             (:COUNTRY-NAME "CA"))
   :ISSUER ((:COMMON-NAME "Entrust Certification Authority - L1A")
            (:ORGANIZATIONAL-UNIT-NAME
             "AND ADDITIONAL TERMS GOVERNING USE AND RELIANCE"
             "CPS CONTAINS IMPORTANT LIMITATIONS OF WARRANTIES AND LIABILITY"
             "www.entrust.net/CPS is incorporated by reference"
             "(c) 2006 Entrust, Inc.")
            (:ORGANIZATION-NAME "Entrust, Inc.") (:COUNTRY-NAME "US")))
CL-USER> (close ***)
T
CL-USER> (assoc :common-name (cl+ssl:x509-certificate-subject **))
(:COMMON-NAME "www.entrust.net")
CL-USER> (setf cl+ssl::*trusted-ca-file* "/tmp/ssl/entrust-root.pem")
"/tmp/ssl/entrust-root.pem"
CL-USER> (cl+ssl::initialize)
2
CL-USER> (get-stream "www.entrust.net")
#<CL+SSL::SSL-STREAM for 5>
CL-USER> (cl+ssl:get-verify-result *)
:OK
CL-USER> (close **)
T
CL-USER> (setf cl+ssl::*cipher-list* "LOW:@STRENGTH")
"LOW:@STRENGTH"
CL-USER> (handler-case (get-stream "ibs.secure-banking.com")
           (error (c) (inspect c)))

The object is a CONDITION of type SSL-ERROR-SSL.
0. QUEUE: "SSL error queue: 
error:14077410:SSL routines:SSL23_GET_SERVER_HELLO:sslv3 alert handshake failure
"
1. CODES: (#S(SSL-ERROR-CODE :LIBRARY :SSL :FUNCTION 119 :REASON 1040))
2. RET: :SSL
3. HANDLE: #.(SB-SYS:INT-SAP #X0813E590)
> q

; No value
CL-USER>
diff -rN -u old-cl+ssl/bio.lisp new-cl+ssl/bio.lisp
--- old-cl+ssl/bio.lisp	2008-08-06 21:05:54.000000000 -0700
+++ new-cl+ssl/bio.lisp	2008-08-06 21:05:54.000000000 -0700
@@ -4,14 +4,8 @@
 
 (in-package cl+ssl)
 
-(defconstant +bio-type-socket+ (logior 5 #x0400 #x0100))
-(defconstant +BIO_FLAGS_READ+ 1)
-(defconstant +BIO_FLAGS_WRITE+ 2)
-(defconstant +BIO_FLAGS_SHOULD_RETRY+ 8)
-(defconstant +BIO_CTRL_FLUSH+ 11)
-
 (cffi:defcstruct bio-method
-  (type :int)
+  (type bio-types)
   (name :pointer)
   (bwrite :pointer)
   (bread :pointer)
@@ -43,9 +37,9 @@
 (defun make-bio-lisp-method ()
   (let ((m (cffi:foreign-alloc 'bio-method)))
     (setf (cffi:foreign-slot-value m 'bio-method 'type)
-	  ;; fixme: this is wrong, but presumably still better than some
-	  ;; random value here.
-	  +bio-type-socket+)
+          ;; fixme: this is wrong, but presumably still better than
+          ;; some random value here.
+          :socket)
     (macrolet ((slot (name)
 		 `(cffi:foreign-slot-value m 'bio-method ,name)))
       (setf (slot 'name) (cffi:foreign-string-alloc "lisp"))
@@ -75,15 +69,12 @@
 (defun clear-retry-flags (bio)
   (setf (cffi:foreign-slot-value bio 'bio 'flags)
 	(logandc2 (cffi:foreign-slot-value bio 'bio 'flags)
-		  (logior +BIO_FLAGS_READ+
-			  +BIO_FLAGS_WRITE+
-			  +BIO_FLAGS_SHOULD_RETRY+))))
+              (bio-flags :read :write :should-retry))))
 
 (defun set-retry-read (bio)
   (setf (cffi:foreign-slot-value bio 'bio 'flags)
 	(logior (cffi:foreign-slot-value bio 'bio 'flags)
-		+BIO_FLAGS_READ+
-		+BIO_FLAGS_SHOULD_RETRY+)))
+            (bio-flags :read :should-retry))))
 
 (cffi:defcallback lisp-read :int ((bio :pointer) (buf :pointer) (n :int))
   bio buf n
@@ -110,10 +101,10 @@
   (error "lisp-puts not implemented"))
 
 (cffi:defcallback lisp-ctrl :int
-  ((bio :pointer) (cmd :int) (larg :long) (parg :pointer))
+  ((bio :pointer) (cmd bio-control) (larg :long) (parg :pointer))
   bio larg parg
-  (cond 
-    ((eql cmd +BIO_CTRL_FLUSH+) 1)
+  (cond
+    ((eq cmd :flush) 1)
     (t
       ;; (warn "lisp-ctrl(~A,~A,~A)" cmd larg parg)
       0)))
diff -rN -u old-cl+ssl/cl+ssl.asd new-cl+ssl/cl+ssl.asd
--- old-cl+ssl/cl+ssl.asd	2008-08-06 21:05:54.000000000 -0700
+++ new-cl+ssl/cl+ssl.asd	2008-08-06 21:05:54.000000000 -0700
@@ -12,16 +12,21 @@
 
 (in-package :cl+ssl-system)
 
+(cl:eval-when (:load-toplevel :execute)
+  (asdf:operate 'asdf:load-op :cffi-grovel))
+
 (defsystem :cl+ssl
   :depends-on (:cffi :trivial-gray-streams :flexi-streams #+sbcl :sb-posix)
   :serial t
   :components
    ((:file "package")
     (:file "reload")
+    (cffi-grovel:grovel-file "grovel")
     (:file "conditions")
     (:file "ffi")
     (:file "ffi-buffer-all")
     #-clisp (:file "ffi-buffer")
     #+clisp (:file "ffi-buffer-clisp")
     (:file "streams")
-    (:file "bio")))
+    (:file "bio")
+    (:file "x509")))
diff -rN -u old-cl+ssl/conditions.lisp new-cl+ssl/conditions.lisp
--- old-cl+ssl/conditions.lisp	2008-08-06 21:05:54.000000000 -0700
+++ new-cl+ssl/conditions.lisp	2008-08-06 21:05:54.000000000 -0700
@@ -6,16 +6,29 @@
 
 (in-package :cl+ssl)
 
-(eval-when (:compile-toplevel :load-toplevel :execute)
-  (defconstant +ssl-error-none+ 0)
-  (defconstant +ssl-error-ssl+ 1)
-  (defconstant +ssl-error-want-read+ 2)
-  (defconstant +ssl-error-want-write+ 3)
-  (defconstant +ssl-error-want-x509-lookup+ 4)
-  (defconstant +ssl-error-syscall+ 5)
-  (defconstant +ssl-error-zero-return+ 6)
-  (defconstant +ssl-error-want-connect+ 7))
-
+;; these definitions are derived from macros found in openssl/err.h:
+(defun ssl-error-get-library (code)
+  (logand #xFF (ash code -24)))
+(defun ssl-error-get-function (code)
+  (logand #xFFF (ash code -12)))
+(defun ssl-error-get-reason (code)
+  (logand #xFFF code))
+
+(defun ssl-error-library (code)
+  (setq code (ssl-error-get-library code))
+  (or (cffi:foreign-enum-keyword
+       'openssl-library-error-codes code
+       :errorp nil)
+   code))
+
+(defstruct ssl-error-code
+  library function reason)
+(defun ssl-error-code (code)
+  ;; note: reason codes below 100 are not specific to a particular
+  ;; openssl module (see err.h)
+  (make-ssl-error-code :library (ssl-error-library code)
+                       :function (ssl-error-get-function code)
+                       :reason (ssl-error-get-reason code)))
 
 ;;; Condition hierarchy
 ;;;
@@ -23,10 +35,12 @@
 (defun write-queued-errors (condition stream)
   (let ((queue (ssl-error-queue condition)))
     (when queue
+      (terpri stream)
       (write-sequence queue stream))))
 
 (define-condition ssl-error (error)
-  ((queue :initform nil :initarg :queue :reader ssl-error-queue)))
+  ((queue :initform nil :initarg :queue :reader ssl-error-queue)
+   (codes :initform nil :initarg :codes :reader ssl-error-codes)))
 
 (define-condition ssl-error/handle (ssl-error)
   ((ret :initarg :ret
@@ -34,7 +48,7 @@
    (handle :initarg :handle
            :reader ssl-error-handle))
   (:report (lambda (condition stream)
-             (format stream "Unspecified error ~A on handle ~A" 
+             (format stream "Unspecified error ~A on handle ~A"
                      (ssl-error-ret condition)
                      (ssl-error-handle condition))
 	     (write-sequence (ssl-error-queue condition) stream))))
@@ -84,7 +98,7 @@
   ()
   (:documentation
    "The operation did not complete; the same TLS/SSL I/O function should be
-    called again later. If, by then, the underlying BIO has data available for 
+    called again later. If, by then, the underlying BIO has data available for
     reading (if the result code is SSL_ERROR_WANT_READ) or allows writing data
     (SSL_ERROR_WANT_WRITE), then some TLS/SSL protocol progress will take place,
     i.e. at least part of an TLS/SSL record will be read or written. Note that
@@ -103,7 +117,7 @@
   ()
   (:documentation
    "The operation did not complete; the same TLS/SSL I/O function should be
-    called again later. If, by then, the underlying BIO has data available for 
+    called again later. If, by then, the underlying BIO has data available for
     reading (if the result code is SSL_ERROR_WANT_READ) or allows writing data
     (SSL_ERROR_WANT_WRITE), then some TLS/SSL protocol progress will take place,
     i.e. at least part of an TLS/SSL record will be read or written. Note that
@@ -136,6 +150,17 @@
                      (ssl-error-ret condition))
 	    (write-queued-errors condition stream))))
 
+;; SSL_ERROR_WANT_ACCEPT
+(define-condition ssl-error-want-accept (ssl-error-want-something)
+  ()
+  (:documentation
+   "Fixme. This error is associated with the special reason BIO_RR_ACCEPT.")
+  (:report (lambda (condition stream)
+            (format stream "The TLS/SSL operation on handle ~A did not complete: It wants an accept first. (return code:  ~A)"
+                     (ssl-error-handle condition)
+                     (ssl-error-ret condition))
+            (write-queued-errors condition stream))))
+
 ;; SSL_ERROR_WANT_X509_LOOKUP
 (define-condition ssl-error-want-x509-lookup (ssl-error-want-something)
   ()
@@ -186,32 +211,39 @@
                      (ssl-error-ret condition))
 	     (write-queued-errors condition stream))))
 
-(defun write-ssl-error-queue (stream)
-  (format stream "SSL error queue: ~%")
-  (loop
-      for error-code = (err-get-error)
-      until (zerop error-code)
-      do (format stream "~a~%" (err-error-string error-code (cffi:null-pointer)))))
+(defun drain-ssl-error-queue ()
+  (let ((stream (make-string-output-stream)))
+    (format stream "SSL error queue: ~%")
+    (values
+     (loop
+         for error-code = (err-get-error)
+         until (zerop error-code)
+         do (format stream "~a~%" (err-error-string error-code (cffi:null-pointer)))
+         collect (ssl-error-code error-code))
+     (get-output-stream-string stream))))
 
 (defun ssl-signal-error (handle syscall error-code original-error)
-  (let ((queue (with-output-to-string (s) (write-ssl-error-queue s))))
-    (if (and (eql error-code #.+ssl-error-syscall+)
-	     (not (zerop original-error)))
-	(error 'ssl-error-syscall
-	       :handle handle
-	       :ret error-code
-	       :queue queue
-	       :syscall syscall)
-      (error (case error-code
-	       (#.+ssl-error-none+ 'ssl-error-none)
-	       (#.+ssl-error-ssl+ 'ssl-error-ssl)
-	       (#.+ssl-error-want-read+ 'ssl-error-want-read)
-	       (#.+ssl-error-want-write+ 'ssl-error-want-write)
-	       (#.+ssl-error-want-x509-lookup+ 'ssl-error-want-x509-lookup)
-	       (#.+ssl-error-zero-return+ 'ssl-error-zero-return)
-	       (#.+ssl-error-want-connect+ 'ssl-error-want-connect)
-	       (#.+ssl-error-syscall+ 'ssl-error-zero-return)
-	       (t 'ssl-error/handle))
-	     :handle handle
-	     :ret error-code
-	     :queue queue))))
+  (multiple-value-bind (error-code-list queue)
+      (drain-ssl-error-queue)
+    (if (and (eq error-code :syscall)
+             (not (zerop original-error)))
+        (error 'ssl-error-syscall
+               :handle handle
+               :ret error-code
+               :queue queue
+               :codes error-code-list
+               :syscall syscall)
+        (error (ecase error-code
+                 (:none 'ssl-error-none)
+                 (:ssl 'ssl-error-ssl)
+                 (:want-read 'ssl-error-want-read)
+                 (:want-write 'ssl-error-want-write)
+                 (:want-x509-lookup 'ssl-error-want-x509-lookup)
+                 (:syscall 'ssl-error-zero-return)
+                 (:zero-return 'ssl-error-zero-return)
+                 (:want-connect 'ssl-error-want-connect)
+                 (:want-accept 'ssl-error-want-accept))
+               :handle handle
+               :ret error-code
+               :queue queue
+               :codes error-code-list))))
diff -rN -u old-cl+ssl/ffi.lisp new-cl+ssl/ffi.lisp
--- old-cl+ssl/ffi.lisp	2008-08-06 21:05:54.000000000 -0700
+++ new-cl+ssl/ffi.lisp	2008-08-06 21:05:54.000000000 -0700
@@ -15,6 +15,8 @@
 (defvar *ssl-global-context* nil)
 (defvar *ssl-global-method* nil)
 (defvar *bio-lisp-method* nil)
+(defvar *trusted-CA-file* nil)
+(defvar *trusted-CA-directory* nil)
 
 (defparameter *blockp* t)
 (defparameter *partial-read-p* nil)
@@ -22,25 +24,27 @@
 (defun ssl-initialized-p ()
   (and *ssl-global-context* *ssl-global-method*))
 
-
 ;;; Constants
 ;;;
 (defconstant +random-entropy+ 256)
 
-(defconstant +ssl-filetype-pem+ 1)
-(defconstant +ssl-filetype-asn1+ 2)
-(defconstant +ssl-filetype-default+ 3)
-
-(defconstant +SSL_CTRL_SET_SESS_CACHE_MODE+ 44)
-(defconstant +SSL_CTRL_MODE+ 33)
-
-(defconstant +SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER+ 2)
-
 ;;; Misc
 ;;;
 (defmacro while (cond &body body)
   `(do () ((not ,cond)) ,@body))
 
+(defun logior-of (enum-category args)
+  (apply #'logior
+         (mapcar #'(lambda (k)
+                     (cffi:foreign-enum-value enum-category k))
+                 args)))
+(defun ssl-mode (&rest args)
+  (logior-of 'ssl-modes args))
+(defun ssl-session-cache-mode (&rest args)
+  (logior-of 'ssl-session-cache-modes args))
+(defun bio-flags (&rest args)
+  (logior-of 'bio-flags args))
+
 
 ;;; Function definitions
 ;;;
@@ -97,7 +101,8 @@
   (rbio :pointer)
   (wbio :pointer))
 (cffi:defcfun ("SSL_get_error" ssl-get-error)
-    :int
+    ;; see SSL ERROR RETURN CODES in grovel spec
+    ssl-errors
   (ssl ssl-pointer)
   (ret :int))
 (cffi:defcfun ("SSL_set_connect_state" ssl-set-connect-state)
@@ -164,8 +169,9 @@
     :int
   (ssl ssl-pointer)
   (str :string)
-  ;; either +ssl-filetype-pem+ or +ssl-filetype-asn1+
-  (type :int))
+  ;; file type code for either pem or asn1.
+  ;; see SSL FILE TYPES section in grovel spec
+  (type ssl-file-types))
 (cffi:defcfun
     ("SSL_CTX_use_RSAPrivateKey_file" ssl-ctx-use-rsa-privatekey-file)
     :int
@@ -176,11 +182,45 @@
   (ssl ssl-pointer)
   (str :string)
   (type :int))
-(cffi:defcfun ("SSL_CTX_load_verify_locations" ssl-ctx-load-verify-locations)
-    :int
-  (ctx ssl-ctx)
-  (CAfile :string)
-  (CApath :string))
+
+(defun ssl-ctx-load-verify-locations (ctx &key ca-file ca-path)
+  "specify the given CA file and/or path as containing default trusted
+root certificates."
+  ;; couldn't get this working as a macro.
+  (labels ((pathstring (s) (namestring (truename s)))
+           (doit ()
+             (cond ((and ca-file ca-path)
+                    (cffi:foreign-funcall "SSL_CTX_load_verify_locations"
+                                          ssl-ctx ctx
+                                          :string (pathstring ca-file)
+                                          :string (pathstring ca-path)
+                                          :int))
+                   (ca-file
+                    (cffi:foreign-funcall "SSL_CTX_load_verify_locations"
+                                          ssl-ctx ctx
+                                          :string (pathstring ca-file)
+                                          :pointer (cffi:null-pointer)
+                                          :int))
+                   (ca-path
+                    (cffi:foreign-funcall "SSL_CTX_load_verify_locations"
+                                          ssl-ctx ctx
+                                          :pointer (cffi:null-pointer)
+                                          :string (pathstring ca-path)
+                                          :int))
+                   (t
+                    (warn "Neither path nor directory specified for CA ~
+                           root certificate store")
+                    1))))
+    (let ((result (doit)))
+      (restart-case
+       (when (zerop result)
+         (error "There was a problem loading the specified CA file/path ~
+                 location(s).  See the OpenSSL error stack for more ~
+                 info (fixme).~%~
+                 Arguments were (~S,~S)." ca-file ca-path))
+       (continue () nil))
+      result)))
+
 (cffi:defcfun ("SSL_CTX_set_client_CA_list" ssl-ctx-set-client-ca-list)
     :void
   (ctx ssl-ctx)
@@ -189,12 +229,15 @@
     ssl-pointer
   (file :string))
 
-(cffi:defcfun ("SSL_CTX_ctrl" ssl-ctx-ctrl)
+(cffi:defcfun ("SSL_CTX_ctrl" ssl-ctx-ctrl*)
     :long
   (ctx ssl-ctx)
-  (cmd :int)
+  (cmd ssl-control)
   (larg :long)
-  (parg :long))
+  (parg :pointer))
+
+(defun ssl-ctx-ctrl (ctx cmd arg)
+  (ssl-ctx-ctrl* ctx cmd arg (cffi:null-pointer)))
 
 
 ;;; Funcall wrapper
@@ -210,17 +253,17 @@
        (when (plusp nbytes)
 	 (return nbytes))
        (let ((error (ssl-get-error handle nbytes)))
-	 (case error
-	   (#.+ssl-error-want-read+
-	    (input-wait stream
-			(ssl-get-fd handle)
-			(ssl-stream-deadline stream)))
-	   (#.+ssl-error-want-write+
-	    (output-wait stream
-			 (ssl-get-fd handle)
-			 (ssl-stream-deadline stream)))
-	   (t
-	    (ssl-signal-error handle func error nbytes)))))))
+         (case error
+           (:want-read
+            (input-wait stream
+                        (ssl-get-fd handle)
+                        (ssl-stream-deadline stream)))
+           (:want-write
+            (output-wait stream
+                         (ssl-get-fd handle)
+                         (ssl-stream-deadline stream)))
+           (t
+            (ssl-signal-error handle func error nbytes)))))))
 
 
 ;;; Waiting for output to be possible
@@ -316,7 +359,8 @@
       (rand-seed ptr +random-entropy+))))
 
 (defun ssl-ctx-set-session-cache-mode (ctx mode)
-  (ssl-ctx-ctrl ctx +SSL_CTRL_SET_SESS_CACHE_MODE+ mode 0))
+  (ssl-ctx-ctrl ctx :set-sess-cache-mode
+                (ssl-session-cache-mode mode)))
 
 (defun initialize (&optional (method 'ssl-v23-method))
   (setf *bio-lisp-method* (make-bio-lisp-method))
@@ -325,7 +369,10 @@
   (init-prng)
   (setf *ssl-global-method* (funcall method))
   (setf *ssl-global-context* (ssl-ctx-new *ssl-global-method*))
-  (ssl-ctx-set-session-cache-mode *ssl-global-context* 3))
+  (ssl-ctx-load-verify-locations *ssl-global-context*
+                                 :ca-file *trusted-ca-file*
+                                 :ca-path *trusted-ca-directory*)
+  (ssl-ctx-set-session-cache-mode *ssl-global-context* :both))
 
 (defun ensure-initialized (&optional (method 'ssl-v23-method))
   (unless (ssl-initialized-p)
diff -rN -u old-cl+ssl/package.lisp new-cl+ssl/package.lisp
--- old-cl+ssl/package.lisp	2008-08-06 21:05:54.000000000 -0700
+++ new-cl+ssl/package.lisp	2008-08-06 21:05:54.000000000 -0700
@@ -10,6 +10,11 @@
   (:use :common-lisp :trivial-gray-streams)
   (:export #:ensure-initialized
            #:reload
-	   #:stream-fd
-	   #:make-ssl-client-stream
-           #:make-ssl-server-stream))
+           #:stream-fd
+           #:make-ssl-client-stream
+           #:make-ssl-server-stream
+           #:get-peer-certificate
+           #:get-verify-result
+           #:x509-certificate
+           #:x509-certificate-subject
+           #:x509-certificate-issuer))
diff -rN -u old-cl+ssl/streams.lisp new-cl+ssl/streams.lisp
--- old-cl+ssl/streams.lisp	2008-08-06 21:05:54.000000000 -0700
+++ new-cl+ssl/streams.lisp	2008-08-06 21:05:54.000000000 -0700
@@ -11,9 +11,15 @@
 
 (in-package :cl+ssl)
 
+(defvar *cipher-list*
+  ;; select high and medium strength ciphers in order of strength
+  ;; excluding those which don't provide authentication (anonymous DH)
+  ;; and excluding RC2 and RC4:
+  "HIGH:MEDIUM:!aNULL:!RC2:!RC4:@STRENGTH")
+
 (defclass ssl-stream
     (fundamental-binary-input-stream
-     fundamental-binary-output-stream 
+     fundamental-binary-output-stream
      trivial-gray-stream-mixin)
   ((ssl-stream-socket
     :initarg :socket
@@ -45,7 +51,7 @@
   (print-unreadable-object (object stream :type t)
     (format stream "for ~A" (ssl-stream-socket object))))
 
-(defclass ssl-server-stream (ssl-stream) 
+(defclass ssl-server-stream (ssl-stream)
   ((certificate
     :initarg :certificate
     :accessor ssl-stream-certificate)
@@ -79,7 +85,7 @@
       (setf (ssl-stream-peeked-byte stream)
             (let* ((*blockp* nil)
                    (b (stream-read-byte stream)))
-              (if (eql b :eof) nil b)))))
+              (if (eq b :eof) nil b)))))
 
 (defmethod stream-read-byte ((stream ssl-stream))
   (or (ssl-stream-peeked-byte stream)
@@ -194,22 +200,17 @@
      (ssl-set-fd handle socket))
     (stream
      (ssl-set-bio handle (bio-new-lisp) (bio-new-lisp))))
-  (ssl-ctx-ctrl handle
-		+SSL_CTRL_MODE+
-		+SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER+
-		0)
+  (ssl-ctx-ctrl handle :mode (ssl-mode :accept-moving-write-buffer))
   socket)
 
 (defun install-key-and-cert (handle key certificate)
   (when key
     (unless (eql 1 (ssl-use-rsa-privatekey-file handle
-						key
-						+ssl-filetype-pem+))
+						key :PEM))
       (error 'ssl-error-initialize :reason (format nil "Can't load RSA private key file ~A" key))))
   (when certificate
     (unless (eql 1 (ssl-use-certificate-file handle
-					     certificate
-					     +ssl-filetype-pem+))
+					     certificate :PEM))
       (error 'ssl-error-initialize
 	     :reason (format nil "Can't load certificate ~A" certificate)))))
 
@@ -218,6 +219,10 @@
       (flexi-streams:make-flexi-stream stream :external-format ef)
       stream))
 
+(defun set-ciphers-for-handle (handle)
+  (when (zerop (ssl-set-cipher-list handle *cipher-list*))
+    (error 'ssl-error-initialize :reason "Can't set SSL cipher list")))
+
 ;; fixme: free the context when errors happen in this function
 (defun make-ssl-client-stream
     (socket &key certificate key (method 'ssl-v23-method) external-format
@@ -233,6 +238,7 @@
         (handle (ssl-new *ssl-global-context*)))
     (setf socket (install-handle-and-bio stream handle socket unwrap-stream-p))
     (ssl-set-connect-state handle)
+    (set-ciphers-for-handle handle)
     (install-key-and-cert handle key certificate)
     (ensure-ssl-funcall stream handle #'ssl-connect handle)
     (handle-external-format stream external-format)))
@@ -254,8 +260,7 @@
         (handle (ssl-new *ssl-global-context*)))
     (setf socket (install-handle-and-bio stream handle socket unwrap-stream-p))
     (ssl-set-accept-state handle)
-    (when (zerop (ssl-set-cipher-list handle "ALL"))
-      (error 'ssl-error-initialize :reason "Can't set SSL cipher list"))
+    (set-ciphers-for-handle handle)
     (install-key-and-cert handle key certificate)
     (ensure-ssl-funcall stream handle #'ssl-accept handle)
     (handle-external-format stream external-format)))
diff -rN -u old-cl+ssl/x509.lisp new-cl+ssl/x509.lisp
--- old-cl+ssl/x509.lisp	1969-12-31 16:00:00.000000000 -0800
+++ new-cl+ssl/x509.lisp	2008-08-06 21:05:54.000000000 -0700
@@ -0,0 +1,142 @@
+(in-package :cl+ssl)
+
+(defstruct x509-certificate
+  ;; fixme; not-valid-before, not-valid-after, serial-number, ...
+  (subject nil :type list)
+  (issuer nil :type list))
+
+(defgeneric get-peer-certificate (stream)
+  (:documentation "Return an x509-certificate corresponding to the
+certificate held by the peer associated with the given stream."))
+
+(defgeneric get-verify-result (stream)
+  (:documentation "Return the verification result of the certificate
+held by the peer associated with the given stream."))
+
+
+(cffi:defcstruct asn1-string
+  (length :int)
+  (type :int)
+  (data (:pointer :unsigned-char))
+  (flags :long))
+
+(cffi:defctype ssl-x509 :pointer) ; x509_st
+(cffi:defctype x509-name-struct :pointer) ; X509_name_st
+(cffi:defctype x509-name-entry :pointer) ; X509_name_entry_st
+(cffi:defctype asn1-object :pointer) ; asn1_object_st
+
+(cffi:defcfun ("SSL_get_peer_certificate" ssl-get-peer-certificate)
+    ssl-x509
+  (s ssl-pointer))
+
+(cffi:defcfun ("SSL_get_verify_result" ssl-get-verify-result)
+    ;; note: x509-verification-results is a constantenum defined in
+    ;; our grovel spec.  if SSL_get_verify_result() returns a value
+    ;; not listed in our enum, cffi signals a simple-error (not a
+    ;; specific error subclass) indicating that case.  otherwise, it
+    ;; returns the appropriate keyword from the list.  The actual C
+    ;; return type is :long.
+    ;;
+    ;; if verification was successful, this function will return :OK
+    ;;
+    ;; see X509 STUFF in grovel spec
+    x509-verification-results
+  (ssl ssl-pointer))
+
+(cffi:defcfun ("X509_get_subject_name" x509-get-subject-name)
+    x509-name-struct
+  (a ssl-x509))
+(cffi:defcfun ("X509_get_issuer_name" x509-get-issuer-name)
+    x509-name-struct
+  (a ssl-x509))
+
+(cffi:defcfun ("X509_NAME_get_entry" x509-name-get-entry)
+    x509-name-entry
+  (name x509-name-struct)
+  (loc :int))
+(cffi:defcfun ("X509_NAME_entry_count" x509-name-get-entry-count)
+    :int
+  (name x509-name-struct))
+(cffi:defcfun ("X509_NAME_ENTRY_get_data" x509-name-entry-get-data)
+    asn1-string
+  (ne x509-name-entry))
+(cffi:defcfun ("X509_NAME_ENTRY_get_object" x509-name-entry-get-object)
+    asn1-string
+  (ne x509-name-entry))
+(cffi:defcfun ("OBJ_obj2nid" asn1-object-to-nid)
+    ;; constantenum defined in grovel.lisp:
+    oid-nid-types
+  (o asn1-object))
+
+
+(define-condition asn1-string-unknown-encoding-error (error)
+  ((type :initarg :type :initform nil)
+   (bytes :initarg :bytes :initform nil))
+  (:report (lambda (c s)
+             (with-slots (type) c
+               (format s "Don't know how to encode/decode strings ~
+                          of type ~S yet" type)))))
+
+(defun collect-bytes (ptr count)
+  (loop for i below count
+        collect (cffi:mem-aref ptr :unsigned-char i)))
+
+(defun x509-decode-asn1-string-data (ptr)
+  (cffi:with-foreign-slots
+      ((type length data) ptr asn1-string)
+    (let ((type (cffi:foreign-enum-keyword
+                 'asn1-likely-string-types type)))
+      (restart-case
+       (when (not (member type
+                          '(:utf8string
+                            :printablestring  ; subset of visible ascii characters
+                            :ia5string        ; ascii characters
+                            :visiblestring))) ; visible ascii characters
+         (error 'asn1-string-unknown-encoding-error
+                :type type
+                :bytes (collect-bytes data length)))
+       (continue () :report "Assume the data is compatible with UTF-8"))
+      ;; utf-8, printable, ia5, and visible should all decode properly
+      ;; when using utf-8 as the external format.
+      (cffi:foreign-string-to-lisp data
+                                   :count length
+                                   :encoding :utf-8))))
+
+(defun simple-asn1-decode (ptr)
+  ;; if the ASN1 data is an unknown type, this function returns (type
+  ;; . bytes) where type is a keyword and a member of the asn1-types
+  ;; cffi enum.
+  (handler-case
+      (x509-decode-asn1-string-data ptr)
+    (asn1-string-unknown-encoding-error (c)
+                                        (with-slots (type bytes) c
+                                          (cons type bytes)))))
+
+(defun decode-all-names (x509-name-struct)
+  (let ((names (loop for i below (x509-name-get-entry-count x509-name-struct)
+                     for entry = (x509-name-get-entry x509-name-struct i)
+                     for object = (x509-name-entry-get-object entry)
+                     for data = (x509-name-entry-get-data entry)
+                     collect
+                     (list (asn1-object-to-nid object) ; e.g., :common-name
+                           (simple-asn1-decode data)))))
+    ;; merge multiple values together:
+    (let ((result nil))
+      (loop for (keyword . values) in names
+            for existing = (assoc keyword result)
+            when existing do (nconc existing values)
+            else do
+            (push (cons keyword values) result))
+      result)))
+
+(defmethod get-peer-certificate ((stream ssl-stream))
+  (let* ((cert (ssl-get-peer-certificate
+                (ssl-stream-handle stream)))
+         (subject (x509-get-subject-name cert))
+         (issuer (x509-get-issuer-name cert)))
+    (make-x509-certificate
+     :subject (decode-all-names subject)
+     :issuer (decode-all-names issuer))))
+
+(defmethod get-verify-result ((stream ssl-stream))
+  (ssl-get-verify-result (ssl-stream-handle stream)))
diff -rN -u old-cl+ssl/grovel.lisp new-cl+ssl/grovel.lisp
--- old-cl+ssl/grovel.lisp	1969-12-31 16:00:00.000000000 -0800
+++ new-cl+ssl/grovel.lisp	2008-08-06 21:05:54.000000000 -0700
@@ -0,0 +1,469 @@
+(in-package :cl+ssl)
+
+(include "openssl/err.h"
+         "openssl/ssl.h"
+         "openssl/bio.h"
+         "openssl/x509.h"
+         "openssl/x509_vfy.h"
+         "openssl/asn1.h"
+         "openssl/objects.h")
+
+
+;;; SSL FILE TYPES (x509.h)
+(constantenum ssl-file-types
+              ((:PEM "X509_FILETYPE_PEM"))
+              ((:ASN1 "X509_FILETYPE_ASN1"))
+              ((:DEFAULT "X509_FILETYPE_DEFAULT")))
+
+
+#.`(,@(labels ((as-string (thing)
+                          (etypecase thing
+                            (string thing)
+                            (symbol (symbol-name thing))
+                            (sequence (coerce thing 'string))))
+               (replace-chars (string target replacement)
+                              (as-string
+                               (loop for char across string
+                                     collect
+                                     (if (char= char target)
+                                         replacement
+                                         char))))
+               (as-keyword (sym)
+                           (intern (replace-chars (as-string sym)
+                                                  #\_ #\-)
+                                   (find-package 'keyword)))
+               (with-prefix (prefix sym)
+                 (format nil "~A_~A" prefix sym))
+               (simple-enum (prefix syms)
+                            (loop for sym in syms
+                                  collect
+                                  `((,(as-keyword sym)
+                                     ,(with-prefix prefix sym))))))
+`(progn
+  ;;; OPENSSL ERROR CODES (err.h)
+  ;; library codes used in composite error codes:
+  ,(let ((ssl-error-lib-syms
+          '(NONE
+            SYS
+            BN
+            RSA
+            DH
+            EVP
+            BUF
+            OBJ
+            PEM
+            DSA
+            X509
+            ASN1
+            CONF
+            CRYPTO
+            EC
+            SSL
+            BIO
+            PKCS7
+            X509V3
+            PKCS12
+            RAND
+            DSO
+            ENGINE
+            OCSP
+            UI
+            COMP
+            ECDSA
+            ECDH
+            STORE
+            USER)))
+        `(constantenum openssl-library-error-codes
+          ,@(simple-enum 'ERR_LIB ssl-error-lib-syms)))
+
+  ;;; SSL STUFF (ssl.h)
+  ;; SSL ERROR RETURN CODES
+  ,(let ((ssl-error-syms
+          '(NONE
+            SSL
+            WANT_READ
+            WANT_WRITE
+            WANT_X509_LOOKUP
+            SYSCALL
+            ZERO_RETURN
+            WANT_CONNECT
+            WANT_ACCEPT)))
+        `(constantenum ssl-errors
+          ,@(simple-enum 'SSL_ERROR ssl-error-syms)))
+  ;; SSL CONTROL
+  ,(let ((ssl-control-syms
+          '(NEED_TMP_RSA
+            SET_TMP_RSA
+            SET_TMP_DH
+            SET_TMP_ECDH
+            SET_TMP_RSA_CB
+            SET_TMP_DH_CB
+            SET_TMP_ECDH_CB
+            GET_SESSION_REUSED
+            GET_CLIENT_CERT_REQUEST
+            GET_NUM_RENEGOTIATIONS
+            CLEAR_NUM_RENEGOTIATIONS
+            GET_TOTAL_RENEGOTIATIONS
+            GET_FLAGS
+            EXTRA_CHAIN_CERT
+            SET_MSG_CALLBACK
+            SET_MSG_CALLBACK_ARG
+            SET_MTU
+            SESS_NUMBER
+            SESS_CONNECT
+            SESS_CONNECT_GOOD
+            SESS_CONNECT_RENEGOTIATE
+            SESS_ACCEPT
+            SESS_ACCEPT_GOOD
+            SESS_ACCEPT_RENEGOTIATE
+            SESS_HIT
+            SESS_CB_HIT
+            SESS_MISSES
+            SESS_TIMEOUTS
+            SESS_CACHE_FULL
+            OPTIONS
+            MODE
+            GET_READ_AHEAD
+            SET_READ_AHEAD
+            SET_SESS_CACHE_SIZE
+            GET_SESS_CACHE_SIZE
+            SET_SESS_CACHE_MODE
+            GET_SESS_CACHE_MODE
+            GET_MAX_CERT_LIST
+            SET_MAX_CERT_LIST)))
+        `(constantenum ssl-control
+          ,@(simple-enum 'SSL_CTRL ssl-control-syms)))
+  ;; SSL MODES
+  ,(let ((ssl-mode-syms
+          '(ENABLE_PARTIAL_WRITE
+            ACCEPT_MOVING_WRITE_BUFFER
+            AUTO_RETRY
+            NO_AUTO_CHAIN)))
+        `(constantenum ssl-modes
+          ,@(simple-enum 'SSL_MODE ssl-mode-syms)))
+  ;; SESSION CACHE MODES
+  ,(let ((ssl-cache-mode-syms
+          '(OFF
+            CLIENT
+            SERVER
+            BOTH
+            NO_AUTO_CLEAR
+            NO_INTERNAL_LOOKUP
+            NO_INTERNAL_STORE
+            NO_INTERNAL)))
+        `(constantenum ssl-session-cache-modes
+          ,@(simple-enum 'SSL_SESS_CACHE ssl-cache-mode-syms)))
+
+  ;;; BIO STUFF (bio.h)
+  ;; BIO TYPES
+  ,(let ((bio-type-syms
+          '(MEM
+            FILE
+            FD
+            SOCKET
+            NULL
+            SSL
+            MD
+            BUFFER
+            CIPHER
+            BASE64
+            CONNECT
+            ACCEPT
+            PROXY_CLIENT
+            PROXY_SERVER
+            NBIO_TEST
+            NULL_FILTER
+            BER
+            BIO
+            LINEBUFFER
+            DGRAM
+            DESCRIPTOR
+            FILTER
+            SOURCE_SINK)))
+        `(constantenum bio-types
+          ,@(simple-enum 'BIO_TYPE bio-type-syms)))
+  ;; BIO FLAGS
+  ,(let ((bio-flag-syms
+          '(READ
+            WRITE
+            IO_SPECIAL
+            RWS
+            SHOULD_RETRY
+            UPLINK
+            BASE64_NO_NL
+            MEM_RDONLY)))
+        `(constantenum bio-flags
+          ,@(simple-enum 'BIO_FLAGS bio-flag-syms)))
+  ;; BIO CONTROL
+  ,(let ((bio-ctrl-syms
+          '(RESET
+            EOF
+            INFO
+            SET
+            GET
+            PUSH
+            POP
+            GET_CLOSE
+            SET_CLOSE
+            PENDING
+            FLUSH
+            DUP
+            WPENDING
+            SET_CALLBACK
+            GET_CALLBACK
+            SET_FILENAME
+            DGRAM_CONNECT
+            DGRAM_SET_CONNECTED
+            DGRAM_SET_RECV_TIMEOUT
+            DGRAM_GET_RECV_TIMEOUT
+            DGRAM_SET_SEND_TIMEOUT
+            DGRAM_GET_SEND_TIMEOUT
+            DGRAM_GET_RECV_TIMER_EXP
+            DGRAM_GET_SEND_TIMER_EXP
+            DGRAM_MTU_DISCOVER
+            DGRAM_QUERY_MTU
+            DGRAM_GET_MTU
+            DGRAM_SET_MTU
+            DGRAM_MTU_EXCEEDED
+            DGRAM_SET_PEER)))
+        `(constantenum bio-control
+          ,@(simple-enum 'BIO_CTRL bio-ctrl-syms)))
+
+  ;;; X509 STUFF (x509_vfy.h)
+  ,(let ((x509-v-err-syms
+          '(UNABLE_TO_GET_ISSUER_CERT
+            UNABLE_TO_GET_CRL
+            UNABLE_TO_DECRYPT_CERT_SIGNATURE
+            UNABLE_TO_DECRYPT_CRL_SIGNATURE
+            UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY
+            CERT_SIGNATURE_FAILURE
+            CRL_SIGNATURE_FAILURE
+            CERT_NOT_YET_VALID
+            CERT_HAS_EXPIRED
+            CRL_NOT_YET_VALID
+            CRL_HAS_EXPIRED
+            ERROR_IN_CERT_NOT_BEFORE_FIELD
+            ERROR_IN_CERT_NOT_AFTER_FIELD
+            ERROR_IN_CRL_LAST_UPDATE_FIELD
+            ERROR_IN_CRL_NEXT_UPDATE_FIELD
+            OUT_OF_MEM
+            DEPTH_ZERO_SELF_SIGNED_CERT
+            SELF_SIGNED_CERT_IN_CHAIN
+            UNABLE_TO_GET_ISSUER_CERT_LOCALLY
+            UNABLE_TO_VERIFY_LEAF_SIGNATURE
+            CERT_CHAIN_TOO_LONG
+            CERT_REVOKED
+            INVALID_CA
+            PATH_LENGTH_EXCEEDED
+            INVALID_PURPOSE
+            CERT_UNTRUSTED
+            CERT_REJECTED
+            SUBJECT_ISSUER_MISMATCH
+            AKID_SKID_MISMATCH
+            AKID_ISSUER_SERIAL_MISMATCH
+            KEYUSAGE_NO_CERTSIGN
+            UNABLE_TO_GET_CRL_ISSUER
+            UNHANDLED_CRITICAL_EXTENSION
+            KEYUSAGE_NO_CRL_SIGN
+            UNHANDLED_CRITICAL_CRL_EXTENSION
+            INVALID_NON_CA
+            PROXY_PATH_LENGTH_EXCEEDED
+            KEYUSAGE_NO_DIGITAL_SIGNATURE
+            PROXY_CERTIFICATES_NOT_ALLOWED
+            INVALID_EXTENSION
+            INVALID_POLICY_EXTENSION
+            NO_EXPLICIT_POLICY
+            UNNESTED_RESOURCE
+            APPLICATION_VERIFICATION)))
+        `(constantenum x509-verification-results
+          ((:ok "X509_V_OK"))
+          ,@(simple-enum 'X509_V_ERR x509-v-err-syms)))
+
+  ;;; ASN1 STUFF (asn1.h)
+  ,(let ((asn1-type-syms
+          '(UNIVERSAL
+            APPLICATION
+            CONTEXT_SPECIFIC
+            PRIVATE
+            CONSTRUCTED
+            PRIMITIVE_TAG
+            PRIMATIVE_TAG
+            APP_CHOOSE
+            OTHER
+            ANY
+            NEG
+            UNDEF
+            EOC
+            BOOLEAN
+            INTEGER
+            NEG_INTEGER
+            BIT_STRING
+            OCTET_STRING
+            NULL
+            OBJECT
+            OBJECT_DESCRIPTOR
+            EXTERNAL
+            REAL
+            ENUMERATED
+            NEG_ENUMERATED
+            UTF8STRING
+            SEQUENCE
+            SET
+            NUMERICSTRING
+            PRINTABLESTRING
+            T61STRING
+            TELETEXSTRING
+            VIDEOTEXSTRING
+            IA5STRING
+            UTCTIME
+            GENERALIZEDTIME
+            GRAPHICSTRING
+            ISO64STRING
+            VISIBLESTRING
+            GENERALSTRING
+            UNIVERSALSTRING
+            BMPSTRING)))
+        `(constantenum asn1-types
+          ,@(simple-enum 'V_ASN1 asn1-type-syms)))
+  ;; asn1 string types
+  ,(let ((likely-asn1-string-type-syms
+          '(UTF8STRING
+            PRINTABLESTRING
+            T61STRING
+            TELETEXSTRING
+            VIDEOTEXSTRING
+            IA5STRING
+            GRAPHICSTRING
+            ISO64STRING
+            VISIBLESTRING
+            GENERALSTRING
+            UNIVERSALSTRING
+            BMPSTRING)))
+        `(constantenum asn1-likely-string-types
+          ,@(simple-enum 'V_ASN1 likely-asn1-string-type-syms)))
+
+  ;; X509 NID OID CODES (objects.h)
+  ;;
+  ;; (tweaked from an autogenerated result made from scanning
+  ;; objects.h)
+  (CONSTANTENUM OID-NID-TYPES ((:UNDEF "NID_undef"))
+   ((:ALGORITHM "NID_algorithm")) ((:RSADSI "NID_rsadsi")) ((:PKCS "NID_pkcs"))
+   ((:MD2 "NID_md2")) ((:MD5 "NID_md5")) ((:RC4 "NID_rc4"))
+   ((:RSA-ENCRYPTION "NID_rsaEncryption"))
+   ((:MD2-WITH-RSA-ENCRYPTION "NID_md2WithRSAEncryption"))
+   ((:MD5-WITH-RSA-ENCRYPTION "NID_md5WithRSAEncryption"))
+   ((:PBE-WITH-MD2-AND-DES-CBC "NID_pbeWithMD2AndDES_CBC"))
+   ((:PBE-WITH-MD5-AND-DES-CBC "NID_pbeWithMD5AndDES_CBC")) ((:X500 "NID_X500"))
+   ((:X509 "NID_X509")) ((:COMMON-NAME "NID_commonName"))
+   ((:COUNTRY-NAME "NID_countryName")) ((:LOCALITY-NAME "NID_localityName"))
+   ((:STATE-OR-PROVINCE-NAME "NID_stateOrProvinceName"))
+   ((:ORGANIZATION-NAME "NID_organizationName"))
+   ((:ORGANIZATIONAL-UNIT-NAME "NID_organizationalUnitName"))
+   ((:RSA "NID_rsa")) ((:PKCS7 "NID_pkcs7")) ((:PKCS7-DATA "NID_pkcs7_data"))
+   ((:PKCS7-SIGNED "NID_pkcs7_signed"))
+   ((:PKCS7-ENVELOPED "NID_pkcs7_enveloped"))
+   ((:PKCS7-SIGNED-AND-ENVELOPED "NID_pkcs7_signedAndEnveloped"))
+   ((:PKCS7-DIGEST "NID_pkcs7_digest"))
+   ((:PKCS7-ENCRYPTED "NID_pkcs7_encrypted")) ((:PKCS3 "NID_pkcs3"))
+   ((:DH-KEY-AGREEMENT "NID_dhKeyAgreement")) ((:DES-ECB "NID_des_ecb"))
+   ((:DES-CFB64 "NID_des_cfb64")) ((:DES-CBC "NID_des_cbc"))
+   ((:DES-EDE "NID_des_ede")) ((:DES-EDE3 "NID_des_ede3"))
+   ((:IDEA-CBC "NID_idea_cbc")) ((:IDEA-CFB64 "NID_idea_cfb64"))
+   ((:IDEA-ECB "NID_idea_ecb")) ((:RC2-CBC "NID_rc2_cbc"))
+   ((:RC2-ECB "NID_rc2_ecb")) ((:RC2-CFB64 "NID_rc2_cfb64"))
+   ((:RC2-OFB64 "NID_rc2_ofb64")) ((:SHA "NID_sha"))
+   ((:SHA-WITH-RSA-ENCRYPTION "NID_shaWithRSAEncryption"))
+   ((:DES-EDE-CBC "NID_des_ede_cbc")) ((:DES-EDE3-CBC "NID_des_ede3_cbc"))
+   ((:DES-OFB64 "NID_des_ofb64")) ((:IDEA-OFB64 "NID_idea_ofb64"))
+   ((:PKCS9 "NID_pkcs9")) ((:PKCS9-EMAIL-ADDRESS "NID_pkcs9_emailAddress"))
+   ((:PKCS9-UNSTRUCTURED-NAME "NID_pkcs9_unstructuredName"))
+   ((:PKCS9-CONTENT-TYPE "NID_pkcs9_contentType"))
+   ((:PKCS9-MESSAGE-DIGEST "NID_pkcs9_messageDigest"))
+   ((:PKCS9-SIGNING-TIME "NID_pkcs9_signingTime"))
+   ((:PKCS9-COUNTERSIGNATURE "NID_pkcs9_countersignature"))
+   ((:PKCS9-CHALLENGE-PASSWORD "NID_pkcs9_challengePassword"))
+   ((:PKCS9-UNSTRUCTURED-ADDRESS "NID_pkcs9_unstructuredAddress"))
+   ((:PKCS9-EXT-CERT-ATTRIBUTES "NID_pkcs9_extCertAttributes"))
+   ((:NETSCAPE "NID_netscape"))
+   ((:NETSCAPE-CERT-EXTENSION "NID_netscape_cert_extension"))
+   ((:NETSCAPE-DATA-TYPE "NID_netscape_data_type"))
+   ((:DES-EDE-CFB64 "NID_des_ede_cfb64"))
+   ((:DES-EDE3-CFB64 "NID_des_ede3_cfb64"))
+   ((:DES-EDE-OFB64 "NID_des_ede_ofb64"))
+   ((:DES-EDE3-OFB64 "NID_des_ede3_ofb64")) ((:SHA1 "NID_sha1"))
+   ((:SHA1-WITH-RSA-ENCRYPTION "NID_sha1WithRSAEncryption"))
+   ((:DSA-WITH-SHA "NID_dsaWithSHA")) ((:DSA-2 "NID_dsa_2"))
+   ((:PBE-WITH-SHA1-AND-RC2-CBC "NID_pbeWithSHA1AndRC2_CBC"))
+   ((:ID-PBKDF2 "NID_id_pbkdf2")) ((:DSA-WITH-SHA1-2 "NID_dsaWithSHA1_2"))
+   ((:NETSCAPE-CERT-TYPE "NID_netscape_cert_type"))
+   ((:NETSCAPE-BASE-URL "NID_netscape_base_url"))
+   ((:NETSCAPE-REVOCATION-URL "NID_netscape_revocation_url"))
+   ((:NETSCAPE-CA-REVOCATION-URL "NID_netscape_ca_revocation_url"))
+   ((:NETSCAPE-RENEWAL-URL "NID_netscape_renewal_url"))
+   ((:NETSCAPE-CA-POLICY-URL "NID_netscape_ca_policy_url"))
+   ((:NETSCAPE-SSL-SERVER-NAME "NID_netscape_ssl_server_name"))
+   ((:NETSCAPE-COMMENT "NID_netscape_comment"))
+   ((:NETSCAPE-CERT-SEQUENCE "NID_netscape_cert_sequence"))
+   ((:DESX-CBC "NID_desx_cbc")) ((:ID-CE "NID_id_ce"))
+   ((:SUBJECT-KEY-IDENTIFIER "NID_subject_key_identifier"))
+   ((:KEY-USAGE "NID_key_usage"))
+   ((:PRIVATE-KEY-USAGE-PERIOD "NID_private_key_usage_period"))
+   ((:SUBJECT-ALT-NAME "NID_subject_alt_name"))
+   ((:ISSUER-ALT-NAME "NID_issuer_alt_name"))
+   ((:BASIC-CONSTRAINTS "NID_basic_constraints"))
+   ((:CRL-NUMBER "NID_crl_number"))
+   ((:CERTIFICATE-POLICIES "NID_certificate_policies"))
+   ((:AUTHORITY-KEY-IDENTIFIER "NID_authority_key_identifier"))
+   ((:BF-CBC "NID_bf_cbc")) ((:BF-ECB "NID_bf_ecb")) ((:BF-CFB64 "NID_bf_cfb64"))
+   ((:BF-OFB64 "NID_bf_ofb64")) ((:MDC2 "NID_mdc2"))
+   ((:MDC2-WITH-RSA "NID_mdc2WithRSA")) ((:RC4-40 "NID_rc4_40"))
+   ((:RC2-40-CBC "NID_rc2_40_cbc")) ((:GIVEN-NAME "NID_givenName"))
+   ((:SURNAME "NID_surname")) ((:INITIALS "NID_initials"))
+   ((:UNIQUE-IDENTIFIER "NID_uniqueIdentifier"))
+   ((:CRL-DISTRIBUTION-POINTS "NID_crl_distribution_points"))
+   ((:MD5-WITH-RSA "NID_md5WithRSA")) ((:SERIAL-NUMBER "NID_serialNumber"))
+   ((:TITLE "NID_title")) ((:DESCRIPTION "NID_description"))
+   ((:CAST5-CBC "NID_cast5_cbc")) ((:CAST5-ECB "NID_cast5_ecb"))
+   ((:CAST5-CFB64 "NID_cast5_cfb64")) ((:CAST5-OFB64 "NID_cast5_ofb64"))
+   ((:PBE-WITH-MD5-AND-CAST5-CBC "NID_pbeWithMD5AndCast5_CBC"))
+   ((:DSA-WITH-SHA1 "NID_dsaWithSHA1")) ((:MD5-SHA1 "NID_md5_sha1"))
+   ((:SHA1-WITH-RSA "NID_sha1WithRSA")) ((:DSA "NID_dsa"))
+   ((:RIPEMD160 "NID_ripemd160")) ((:RIPEMD160-WITH-RSA "NID_ripemd160WithRSA"))
+   ((:RC5-CBC "NID_rc5_cbc")) ((:RC5-ECB "NID_rc5_ecb"))
+   ((:RC5-CFB64 "NID_rc5_cfb64")) ((:RC5-OFB64 "NID_rc5_ofb64"))
+   ((:RLE-COMPRESSION "NID_rle_compression"))
+   ((:ZLIB-COMPRESSION "NID_zlib_compression"))
+   ((:EXT-KEY-USAGE "NID_ext_key_usage")) ((:ID-PKIX "NID_id_pkix"))
+   ((:ID-KP "NID_id_kp")) ((:SERVER-AUTH "NID_server_auth"))
+   ((:CLIENT-AUTH "NID_client_auth")) ((:CODE-SIGN "NID_code_sign"))
+   ((:EMAIL-PROTECT "NID_email_protect")) ((:TIME-STAMP "NID_time_stamp"))
+   ((:MS-CODE-IND "NID_ms_code_ind")) ((:MS-CODE-COM "NID_ms_code_com"))
+   ((:MS-CTL-SIGN "NID_ms_ctl_sign")) ((:MS-SGC "NID_ms_sgc"))
+   ((:MS-EFS "NID_ms_efs")) ((:NS-SGC "NID_ns_sgc"))
+   ((:DELTA-CRL "NID_delta_crl")) ((:CRL-REASON "NID_crl_reason"))
+   ((:INVALIDITY-DATE "NID_invalidity_date")) ((:SXNET "NID_sxnet"))
+   ((:PBE-WITH-SHA1-AND-128-BIT-RC4 "NID_pbe_WithSHA1And128BitRC4"))
+   ((:PBE-WITH-SHA1-AND-40-BIT-RC4 "NID_pbe_WithSHA1And40BitRC4"))
+   ((:PBE-WITH-SHA1-AND-3-KEY-TRIPLE-DES-CBC
+     "NID_pbe_WithSHA1And3_Key_TripleDES_CBC"))
+   ((:PBE-WITH-SHA1-AND-2-KEY-TRIPLE-DES-CBC
+     "NID_pbe_WithSHA1And2_Key_TripleDES_CBC"))
+   ((:PBE-WITH-SHA1-AND-128-BIT-RC2-CBC "NID_pbe_WithSHA1And128BitRC2_CBC"))
+   ((:PBE-WITH-SHA1-AND-40-BIT-RC2-CBC "NID_pbe_WithSHA1And40BitRC2_CBC"))
+   ((:KEY-BAG "NID_keyBag"))
+   ((:PKCS8-SHROUDED-KEY-BAG "NID_pkcs8ShroudedKeyBag"))
+   ((:CERT-BAG "NID_certBag")) ((:CRL-BAG "NID_crlBag"))
+   ((:SECRET-BAG "NID_secretBag"))
+   ((:SAFE-CONTENTS-BAG "NID_safeContentsBag")) ((:PBES2 "NID_pbes2"))
+   ((:PBMAC1 "NID_pbmac1")) ((:HMAC-WITH-SHA1 "NID_hmacWithSHA1"))
+   ((:ID-QT-CPS "NID_id_qt_cps")) ((:ID-QT-UNOTICE "NID_id_qt_unotice"))
+   ((:RC2-64-CBC "NID_rc2_64_cbc"))
+   ((:SMIME-CAPABILITIES "NID_SMIMECapabilities"))
+   ((:PBE-WITH-MD2-AND-RC2-CBC "NID_pbeWithMD2AndRC2_CBC"))
+   ((:PBE-WITH-MD5-AND-RC2-CBC "NID_pbeWithMD5AndRC2_CBC"))
+   ((:PBE-WITH-SHA1-AND-DES-CBC "NID_pbeWithSHA1AndDES_CBC"))
+   ((:MS-EXT-REQ "NID_ms_ext_req")) ((:EXT-REQ "NID_ext_req"))
+   ((:NAME "NID_name")) ((:DN-QUALIFIER "NID_dnQualifier"))
+   ((:ID-PE "NID_id_pe")) ((:ID-AD "NID_id_ad"))
+   ((:INFO-ACCESS "NID_info_access")) ((:AD-OCSP "NID_ad_OCSP"))
+   ((:AD-CA-ISSUERS "NID_ad_ca_issuers")) ((:OCSP-SIGN "NID_OCSP_sign"))))))


