commit 53c86fc6436925699a59d165936c83f980f5b53e
parent 9b173e2b93cc88b06b8fd7f29cd1655edc3df89f
Author: Tomas Hlavaty <tom@logand.com>
Date: Sun, 3 Aug 2014 21:04:19 +0200
tls added
Diffstat:
A | tls.lisp | | | 709 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
1 file changed, 709 insertions(+), 0 deletions(-)
diff --git a/tls.lisp b/tls.lisp
@@ -0,0 +1,709 @@
+;;; Copyright (C) 2014 Tomas Hlavaty <tom@logand.com>
+;;;
+;;; Permission is hereby granted, free of charge, to any person
+;;; obtaining a copy of this software and associated documentation
+;;; files (the "Software"), to deal in the Software without
+;;; restriction, including without limitation the rights to use, copy,
+;;; modify, merge, publish, distribute, sublicense, and/or sell copies
+;;; of the Software, and to permit persons to whom the Software is
+;;; furnished to do so, subject to the following conditions:
+;;;
+;;; The above copyright notice and this permission notice shall be
+;;; included in all copies or substantial portions of the Software.
+;;;
+;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+;;; EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+;;; MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+;;; NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+;;; HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+;;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+;;; DEALINGS IN THE SOFTWARE.
+
+(defpackage :rw.tls
+ (:use :cl))
+
+(in-package :rw.tls)
+
+;;tshark -i wlp3s0 -V >~/git/cl-rw/tls.log
+;;gnutls-cli wikipedia.org
+
+;; https://en.wikipedia.org/wiki/Transport_Layer_Security
+
+(defun next-u8 (reader)
+ (rw:next-u8 reader))
+
+(defun next-u16 (reader)
+ (rw:next-u16 reader))
+
+(defun next-u24 (reader)
+ (rw:next-u24 reader))
+
+(defun next-u32 (reader)
+ (rw:next-u32 reader))
+
+(defun write-u8 (writer x)
+ (rw:write-u8 writer x))
+
+(defun write-u16 (writer x)
+ (rw:write-u16 writer x))
+
+(defun write-u24 (writer x)
+ (assert (<= 0 x #.(1- (expt 2 24))))
+ (write-u8 writer (ash x -16))
+ (write-u8 writer (logand #xff (ash x -8)))
+ (write-u8 writer (logand #xff x)))
+
+(defun write-u32 (writer x)
+ (rw:write-u32 writer x))
+
+(defun fname (x)
+ (intern (format nil "~a" x)))
+
+(defun mname (x)
+ (intern (format nil "MAKE-~a" x)))
+
+(defun rname (x)
+ (intern (format nil "NEXT-~a" x)))
+
+(defun wname (x)
+ (intern (format nil "WRITE-~a" x)))
+
+(defmacro defenum (name (&key nbits) &body alist)
+ (let ((fname (fname name))
+ (sname (intern (format nil "~a-SYMBOLS" name)))
+ (cname (intern (format nil "~a-CODES" name)))
+ (rname (rname name))
+ (wname (wname name)))
+ `(let* ((alist ',alist)
+ (symbols (mapcar #'car alist))
+ (codes (mapcar #'cdr alist)))
+ (defun ,fname (x)
+ (etypecase x
+ (symbol (cdr (assoc x alist)))
+ (integer (car (rassoc x alist)))))
+ (defun ,sname () symbols)
+ (defun ,cname () codes)
+ (defun ,rname (reader)
+ (let ((z (,fname (, (ecase nbits
+ (8 'rw:next-u8)
+ (16 'rw:next-u16))
+ reader))))
+ (assert z)
+ z))
+ (defun ,wname (writer x)
+ (, (ecase nbits
+ (8 'rw:write-u8)
+ (16 'rw:write-u16))
+ writer
+ (etypecase x
+ (symbol (,fname x))
+ (integer (when (member x codes) x))))))))
+
+(defenum $AlertLevel (:nbits 8)
+ (WARNING . 1)
+ (FATAL . 2))
+
+(defenum $AlertDescription (:nbits 8)
+ (CLOSE_NOTIFY . 0)
+ (UNEXPECTED_MESSAGE . 10)
+ (BAD_RECORD_MAC . 20)
+ (DECRYPTION_FAILED_RESERVED . 21)
+ (RECORD_OVERFLOW . 22)
+ (DECOMPRESSION_FAILURE . 30)
+ (HANDSHAKE_FAILURE . 40)
+ (NO_CERTIFICATE_RESERVED . 41)
+ (BAD_CERTIFICATE . 42)
+ (UNSUPPORTED_CERTIFICATE . 43)
+ (CERTIFICATE_REVOKED . 44)
+ (CERTIFICATE_EXPIRED . 45)
+ (CERTIFICATE_UNKNOWN . 46)
+ (ILLEGAL_PARAMETER . 47)
+ (UNKNOWN_CA . 48)
+ (ACCESS_DENIED . 49)
+ (DECODE_ERROR . 50)
+ (DECRYPT_ERROR . 51)
+ (EXPORT_RESTRICTION_RESERVED . 60)
+ (PROTOCOL_VERSION . 70)
+ (INSUFFICIENT_SECURITY . 71)
+ (INTERNAL_ERROR . 80)
+ (USER_CANCELED . 90)
+ (NO_RENEGOTIATION . 100)
+ (UNSUPPORTED_EXTENSION . 110))
+
+(defenum $CipherSuite (:nbits 16)
+ (TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA . #X0013)
+ (TLS_DHE_DSS_WITH_AES_128_CBC_SHA . #X0032)
+ (TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 . #X0040)
+ (TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 . #X00A2)
+ (TLS_DHE_DSS_WITH_AES_256_CBC_SHA . #X0038)
+ (TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 . #X006A)
+ (TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 . #X00A3)
+ (TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA . #X0044)
+ (TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 . #X00BD)
+ (TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 . #XC080)
+ (TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA . #X0087)
+ (TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 . #X00C3)
+ (TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 . #XC081)
+ (TLS_DHE_DSS_WITH_RC4_128_SHA . #X0066)
+ (TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA . #X0016)
+ (TLS_DHE_RSA_WITH_AES_128_CBC_SHA . #X0033)
+ (TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 . #X0067)
+ (TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 . #X009E)
+ (TLS_DHE_RSA_WITH_AES_256_CBC_SHA . #X0039)
+ (TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 . #X006B)
+ (TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 . #X009F)
+ (TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA . #X0045)
+ (TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 . #X00BE)
+ (TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 . #XC07C)
+ (TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA . #X0088)
+ (TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 . #X00C4)
+ (TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 . #XC07D)
+ (TLS_DH_ANON_WITH_3DES_EDE_CBC_SHA . #X001B)
+ (TLS_DH_ANON_WITH_AES_128_CBC_SHA . #X0034)
+ (TLS_DH_ANON_WITH_AES_128_CBC_SHA256 . #X006C)
+ (TLS_DH_ANON_WITH_AES_256_CBC_SHA . #X003A)
+ (TLS_DH_ANON_WITH_AES_256_CBC_SHA256 . #X006D)
+ (TLS_DH_ANON_WITH_RC4_128_MD5 . #X0018)
+ (TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA . #X000D)
+ (TLS_DH_DSS_WITH_AES_128_CBC_SHA . #X0030)
+ (TLS_DH_DSS_WITH_AES_128_CBC_SHA256 . #X003E)
+ (TLS_DH_DSS_WITH_AES_256_CBC_SHA . #X0036)
+ (TLS_DH_DSS_WITH_AES_256_CBC_SHA256 . #X0068)
+ (TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA . #X0010)
+ (TLS_DH_RSA_WITH_AES_128_CBC_SHA . #X0031)
+ (TLS_DH_RSA_WITH_AES_128_CBC_SHA256 . #X003F)
+ (TLS_DH_RSA_WITH_AES_256_CBC_SHA . #X0037)
+ (TLS_DH_RSA_WITH_AES_256_CBC_SHA256 . #X0069)
+ (TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA . #XC008)
+ (TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA . #XC009)
+ (TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 . #XC023)
+ (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 . #XC02B)
+ (TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA . #XC00A)
+ (TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 . #XC024)
+ (TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 . #XC02C)
+ (TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 . #XC072)
+ (TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 . #XC086)
+ (TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 . #XC073)
+ (TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 . #XC087)
+ (TLS_ECDHE_ECDSA_WITH_RC4_128_SHA . #XC007)
+ (TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA . #XC012)
+ (TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA . #XC013)
+ (TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 . #XC027)
+ (TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 . #XC02F)
+ (TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA . #XC014)
+ (TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 . #XC028)
+ (TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 . #XC030)
+ (TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 . #XC076)
+ (TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 . #XC08A)
+ (TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 . #XC077)
+ (TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 . #XC08B)
+ (TLS_ECDHE_RSA_WITH_RC4_128_SHA . #XC011)
+ (TLS_NULL_WITH_NULL_NULL . #X0000)
+ (TLS_RSA_WITH_3DES_EDE_CBC_SHA . #X000A)
+ (TLS_RSA_WITH_AES_128_CBC_SHA . #X002F)
+ (TLS_RSA_WITH_AES_128_CBC_SHA256 . #X003C)
+ (TLS_RSA_WITH_AES_128_GCM_SHA256 . #X009C)
+ (TLS_RSA_WITH_AES_256_CBC_SHA . #X0035)
+ (TLS_RSA_WITH_AES_256_CBC_SHA256 . #X003D)
+ (TLS_RSA_WITH_AES_256_GCM_SHA384 . #X009D)
+ (TLS_RSA_WITH_CAMELLIA_128_CBC_SHA . #X0041)
+ (TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 . #X00BA)
+ (TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 . #XC07A)
+ (TLS_RSA_WITH_CAMELLIA_256_CBC_SHA . #X0084)
+ (TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 . #X00C0)
+ (TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 . #XC07B)
+ (TLS_RSA_WITH_NULL_MD5 . #X0001)
+ (TLS_RSA_WITH_NULL_SHA . #X0002)
+ (TLS_RSA_WITH_NULL_SHA256 . #X003B)
+ (TLS_RSA_WITH_RC4_128_MD5 . #X0004)
+ (TLS_RSA_WITH_RC4_128_SHA . #X0005))
+
+(defenum $ClientCertificateType (:nbits 8)
+ (rsa_sign . 1)
+ (dss_sign . 2)
+ (rsa_fixed_dh . 3)
+ (dss_fixed_dh . 4)
+ (rsa_ephemeral_dh_RESERVED . 5)
+ (dss_ephemeral_dh_RESERVED . 6)
+ (fortezza_dms_RESERVED . 20))
+
+(defenum $CompressionMethod (:nbits 8)
+ (null . 0))
+
+(defenum $ContentType (:nbits 8)
+ (CHANGE_CIPHER_SPEC . 20)
+ (ALERT . 21)
+ (HANDSHAKE . 22)
+ (APPLICATION_DATA . 23))
+
+(defenum $ContentVersion (:nbits 16)
+ (SSL3.0 . #x0300)
+ (TLS1.2 . #x0303))
+
+(defenum $ExtensionType (:nbits 16)
+ (ec_point_formats . #x000b)
+ (elliptic_curves . #x000a)
+ (renegotiation_info . #xff01)
+ (SessionTicket_TLS . #x0023)
+ (server_name . #x0000)
+ (signature_algorithms . #x000d)
+ (status_request . #x0005))
+
+(defenum $HandshakeType (:nbits 8)
+ (HELLO_REQUEST . 0)
+ (CLIENT_HELLO . 1)
+ (SERVER_HELLO . 2)
+ (CERTIFICATE . 11)
+ (SERVER_KEY_EXCHANGE . 12)
+ (CERTIFICATE_REQUEST . 13)
+ (SERVER_HELLO_DONE . 14)
+ (CERTIFICATE_VERIFY . 15)
+ (CLIENT_KEY_EXCHANGE . 16)
+ (FINISHED . 20))
+
+(defenum $HashAlgorith (:nbits 8)
+ (none . 0)
+ (md5 . 1)
+ (sha1 . 2)
+ (sha224 . 3)
+ (sha256 . 4)
+ (sha384 . 5)
+ (sha512 . 6))
+
+(defenum $SignatureAlgorithm (:nbits 8)
+ (anonymous . 0)
+ (rsa . 1)
+ (dsa . 2)
+ (ecdsa . 3))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun PublicValueEncoding ()
+ ;; If the client has sent a certificate which contains a suitable
+ ;; Diffie-Hellman key (for fixed_dh client authentication), then
+ ;; Yc is implicit and does not need to be sent again. In this
+ ;; case, the client key exchange message will be sent, but it MUST
+ ;; be empty.
+ 'implicit)
+
+(defun KeyExchangeAlgorithm ()
+ ;; dhe_dss dhe_rsa dh_anon rsa dh_dss dh_rsa
+ 'dhe_rsa)
+
+;;;;;;;;;;;;;;
+
+(defun aname (struc &optional slot)
+ (intern (format nil "~a-~a" struc slot)))
+
+(defun defun-rname-slot (slot)
+ (destructuring-bind (ty na &key length size min max compute next) slot
+ `(,na
+ , (flet ((r1 ()
+ (if (listp ty)
+ `(ecase ,(cadr ty)
+ ,@(loop
+ for (nm ty) in (cddr ty)
+ collect (if ty
+ `(,nm (,(rname ty) r))
+ `(,nm))))
+ `(,(rname ty) r))))
+ (cond
+ ((or compute next)
+ (assert (eq 'computed ty))
+ (assert (not (or length size min max)))
+ (or compute next))
+ (length
+ `(let ((l (,(rname length) r))
+ (b (make-octet-buffer 100)))
+ ,@(when min `((assert (<= ,min l))))
+ ,@(when max `((assert (<= l ,max))))
+ ,@(when (integerp size) `((assert (= l ,size))))
+ (dotimes (i l)
+ (vector-push-extend (next-u8 r) b))
+ ,(if (eq 'u8 ty)
+ 'b
+ (if size
+ `(let ((r (rw:peek-reader (rw:reader b))))
+ (loop
+ while (rw:peek r)
+ collect ,(r1)))
+ `(let ((r (rw:reader b)))
+ ,(r1))))))
+ (size
+ (assert (eq 'u8 ty))
+ `(loop for i from 0 below ,size collect ,(r1)))
+ (t
+ `(let ((v ,(r1)))
+ ,@(when min `((assert (<= ,min v))))
+ ,@(when max `((assert (<= v ,max))))
+ v)))))))
+
+(defun defun-rname (name slots)
+ `(defun ,(rname name) (r)
+ (let* (,@(mapcar 'defun-rname-slot slots))
+ (,(mname name)
+ ,@(loop
+ for slot in slots
+ appending (let ((na (cadr slot)))
+ (list (intern (symbol-name na) :keyword) na)))))))
+
+(defun defun-wname (name slots)
+ `(defun ,(wname name) (w x)
+ ,@(loop
+ for slot in slots
+ collect
+ (destructuring-bind (ty na &key length size min max compute next) slot
+ (flet ((w1 ()
+ (if (listp ty)
+ (ecase (car ty)
+ (ecase `(ecase (,(aname name (cadr ty)) x)
+ ,@(loop
+ for (nm ty) in (cddr ty)
+ collect
+ (if ty
+ `(,nm (,(wname ty) w v))
+ `(,nm))))))
+ `(,(wname ty) w v))))
+ (cond
+ ((or compute next)
+ (assert (eq 'computed ty))
+ (assert (not (or length size min max)))
+ (when compute
+ `(setf (,(aname name na) x) ,compute)))
+ (length
+ `(let ((v (,(aname name na) x))
+ (b (make-octet-buffer 100)))
+ (let ((w (rw:writer b)))
+ ,(cond
+ (size
+ `(if (listp v)
+ (loop for v in v do ,(w1))
+ (loop for v across v do ,(w1))))
+ (t (w1))))
+ (let ((l (length b)))
+ ,@(when min `((assert (<= ,min l))))
+ ,@(when max `((assert (<= l ,max))))
+ ,@(when (integerp size) `((assert (= l ,size))))
+ (,(wname length) w l))
+ (loop for e across b do (write-u8 w e))))
+ (size
+ (assert (eq 'u8 ty))
+ `(let ((v (,(aname name na) x)))
+ ,@ (when (or min max (integerp size))
+ `((let ((l (length v)))
+ ,@(when min `((assert (<= ,min l))))
+ ,@(when max `((assert (<= l ,max))))
+ ,@(when (integerp size) `((assert (= l ,size)))))))
+ (if (listp v)
+ (loop for v in v do ,(w1))
+ (loop for v across v do ,(w1)))))
+ (t
+ `(let ((v (,(aname name na) x)))
+ ,@(when min `((assert (<= ,min v))))
+ ,@(when max `((assert (<= v ,max))))
+ ,(w1)))))))))
+
+(defmacro defstruc (name () &body slots)
+ `(progn
+ (defstruct ,(fname name) ,@(mapcar #'cadr slots))
+ ,(defun-rname name slots)
+ ,(defun-wname name slots)))
+
+(defstruc $Alert ()
+ ($AlertLevel level)
+ ($AlertDescription description))
+
+#+nil
+(defstruc $ASN.1Cert ()
+ (u8 data :min 0 :max #.(1- (expt 2 24))))
+
+(defstruc %$Certificate ()
+ (u8 #+nil $ASN.1Cert data :length u24 :min 0 :max #.(1- (expt 2 24)))
+ (computed der :next (rw.der:decode (rw:reader data))))
+
+(defstruc $Certificate ()
+ (%$Certificate list :length u24 :min 0 :max #.(1- (expt 2 24)) :size t))
+
+(defstruc $ClientDiffieHellmanPublic ()
+ (computed type :compute (PublicValueEncoding))
+ ((ecase type
+ (implicit)
+ (explicit $dh_Yc))
+ dh_public))
+
+(defstruc $ClientHello ()
+ ($ContentVersion #+nil $ProtocolVersion version)
+ ($Random random)
+ ($SessionID session_id)
+ ($CipherSuite cipher_suites :length u16 :min 2 :max #.(- (expt 2 16) 2) :size t)
+ ($CompressionMethod compression_methods :length u8 :min 1 :max #.(1- (expt 2 8)) :size t)
+ ($Extension extensions :length u16 :min 0 :max #.(1- (expt 2 16)) :size t))
+
+(defstruc $ClientKeyExchange ()
+ (computed type :compute (KeyExchangeAlgorithm))
+ ((ecase type
+ (rsa $EncryptedPreMasterSecret)
+ ((dhe_dss dhe_rsa dh_dss dh_rsa dh_anon) $ClientDiffieHellmanPublic))
+ keys))
+
+(defstruc $dh_Yc ()
+ (u8 data :length u16 :min 1 :max #.(1- (expt 2 16))))
+
+(defstruc $EncryptedPreMasterSecret ()
+ ($PreMasterSecret pubkey_encrypted))
+
+(defstruc $Extension ()
+ ($ExtensionType type)
+ #+nil
+ (ecase type
+ (status_request)
+ (server_name)
+ (renegotiation_info)
+ (SessionTicket_TLS)
+ (elliptic_curves)
+ (ec_point_formats)
+ (signature_algorithms))
+ (u8 data :length u16 :min 0 :max #.(1- (expt 2 16)) :size t))
+
+(defstruc $Handshake ()
+ ($HandshakeType type)
+ ((ecase type
+ (CERTIFICATE $Certificate)
+ (CLIENT_HELLO $ClientHello)
+ (CLIENT_KEY_EXCHANGE $ClientKeyExchange)
+ (SERVER_HELLO $ServerHello)
+ (SERVER_HELLO_DONE)
+ (SERVER_KEY_EXCHANGE #+nil $ServerKeyExchange))
+ data :length u24))
+
+(defstruc $PreMasterSecret ()
+ ($ContentVersion #+nil ProtocolVersion client_version)
+ (u8 random :size 46))
+
+(defstruc $Random ()
+ (u32 gmt_unix_time)
+ (u8 random_bytes :size 28))
+
+(defstruc $Record ()
+ ($ContentType type)
+ (u16 #+nil ContentVersion version)
+ ((ecase type
+ (ALERT $Alert)
+ (HANDSHAKE $Handshake))
+ data :length u16 :min 1 :max 16383)
+ #+nil
+ (u8 data :length u16 :min 1 :max 16383 :size t))
+
+#+nil
+(defstruc $ServerDHParams () ;;;;
+ (u8 dh_p :min 1 :max #.(1- (expt 2 16)) :size t)
+ (u8 dh_g :min 1 :max #.(1- (expt 2 16)) :size t)
+ (u8 dh_Ys :min 1 :max #.(1- (expt 2 16)) :size t))
+
+(defstruc %$ServerDHParams2 ()
+ ($ServerDHParams params)
+ ($signed_params signed_params))
+
+(defstruc $ServerHello ()
+ ($ContentVersion #+nil ProtocolVersion version)
+ ($Random random)
+ ($SessionID session_id)
+ ($CipherSuite cipher_suite)
+ ($CompressionMethod compression_method)
+ ($Extension extensions :length u16 :min 0 :max #.(1- (expt 2 16)) :size t))
+
+#+nil
+(defstruc $ServerKeyExchange ()
+ (u8 data :min 1 :max #.(1- (expt 2 16)) :size t)
+ #+nil
+ ($KeyExchangeAlgorithm type)
+ #+nil
+ ((ecase type
+ (dh_anon $ServerDHParams)
+ ((dhe_dss dhe_rsa) %$ServerDHParams2)
+ ((rsa dh_dss dh_rsa)))
+ data))
+
+(defstruc $SessionID ()
+ (u8 data :length u8 :min 0 :max 32 :size t))
+
+(defstruc $signed_params ()
+ (u8 client_random :size 32)
+ (u8 server_random :size 32)
+ ($ServerDHParams params2))
+
+;; struct {
+;; HashAlgorithm hash
+;; SignatureAlgorithm signature
+;; } SignatureAndHashAlgorithm
+
+;; SignatureAndHashAlgorithm
+;; supported_signature_algorithms<2..2^16-1>
+
+(defun make-octet-buffer (length)
+ (make-array length
+ :element-type '(unsigned-byte 8)
+ :initial-element 0
+ :adjustable t
+ :fill-pointer 0))
+
+(defun random-octets (length)
+ (loop
+ for i from 0 below length
+ collect (random 256)))
+
+(defun universal-time-to-unix (x)
+ (- x #.(encode-universal-time 0 0 0 1 1 1970 0)))
+
+;;(universal-time-to-unix (encode-universal-time 19 22 23 28 7 2014 0)) ;; TODO broken
+
+(defun test ()
+ (let ((b (make-octet-buffer 100)))
+ (write-$Record
+ (rw:writer b)
+ (make-$Record
+ :type 'HANDSHAKE
+ :version ($ContentVersion 'SSL3.0)
+ :data (make-$Handshake
+ :type 'CLIENT_HELLO
+ :data (make-$ClientHello
+ :version 'TLS1.2
+ :random (make-$Random
+ :gmt_unix_time (universal-time-to-unix (get-universal-time))
+ :random_bytes (random-octets 28))
+ :session_id (make-$SessionID #+nil :data #+nil(random-octets 32))
+ :cipher_suites '(TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+ TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256
+ TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+ TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256
+ TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384
+ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+ TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+ TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA
+ TLS_RSA_WITH_AES_128_GCM_SHA256
+ TLS_RSA_WITH_AES_256_GCM_SHA384
+ TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ TLS_RSA_WITH_AES_128_CBC_SHA
+ TLS_RSA_WITH_AES_128_CBC_SHA256
+ TLS_RSA_WITH_AES_256_CBC_SHA
+ TLS_RSA_WITH_AES_256_CBC_SHA256
+ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+ TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA
+ TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ TLS_RSA_WITH_RC4_128_SHA
+ TLS_RSA_WITH_RC4_128_MD5
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256
+ TLS_DHE_RSA_WITH_AES_256_GCM_SHA384
+ TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256
+ TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA256
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA256
+ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA
+ TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256
+ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA
+ TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256
+ TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA
+ TLS_DHE_DSS_WITH_AES_128_GCM_SHA256
+ TLS_DHE_DSS_WITH_AES_256_GCM_SHA384
+ TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256
+ TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA256
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA256
+ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA
+ TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256
+ TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA
+ TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256
+ TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA
+ TLS_DHE_DSS_WITH_RC4_128_SHA)
+ :compression_methods (list 'null)
+ :extensions (list
+ (make-$Extension :type 'status_request
+ :data '(1 0 0 0 0))
+ (make-$Extension :type 'server_name
+ :data '(0 #x10 0 0 #xd #x77 #x69 #x6b #x69 #x70 #x65 #x64 #x69 #x61 #x2e #x6f #x72 #x67))
+ (make-$Extension :type 'renegotiation_info
+ :data '(0))
+ (make-$Extension :type 'SessionTicket_TLS :data nil)
+ (make-$Extension :type 'elliptic_curves
+ :data '(0 10 0 #x13 0 #x15 0 #x17 0 #x18 0 #x19))
+ (make-$Extension :type 'ec_point_formats
+ :data '(1 0))
+ (make-$Extension :type 'signature_algorithms
+ :data '(0 #x1a 4 1 4 2 4 3 5 1 5 3 6 1 6 3 3 1 3 2 3 3 2 1 2 2 2 3)))))))
+ b))
+
+;;(print (test))
+
+(defun test2 ()
+ (let ((b (make-octet-buffer 100)))
+ (write-$Record
+ (rw:writer b)
+ (make-$Record
+ :type 'HANDSHAKE
+ :version ($ContentVersion 'SSL3.0)
+ :data (make-$Handshake
+ :type 'CLIENT_KEY_EXCHANGE
+ :data (make-$ClientKeyExchange
+ :keys (make-$ClientDiffieHellmanPublic
+ :dh_public nil)))))
+ b))
+
+;;(print (test2))
+
+(let ((saved (test)))
+ (with-open-file (s "/tmp/a"
+ :direction :output
+ :if-exists :supersede
+ :if-does-not-exist :create
+ :element-type '(unsigned-byte 8))
+ (write-sequence saved s))
+ (with-open-file (s "/tmp/a" :element-type '(unsigned-byte 8))
+ (next-$Record (rw:byte-reader s))
+ #+nil(next-$ClientHello (record-reader (rw:byte-reader s)))))
+
+(with-open-stream (s (rw.socket:make-tcp-client-socket "wikipedia.org" 443))
+ (write-sequence (test) s) ;; client hello
+ (finish-output s)
+ (print
+ (list (next-$Record (rw:byte-reader s)) ;; server hello
+ (next-$Record (rw:byte-reader s)) ;; certificate
+ (next-$Record (rw:byte-reader s)) ;; server key exchange
+ (next-$Record (rw:byte-reader s)) ;; server hello done
+ ))
+ ;;TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ ;; client key exchange
+ (write-sequence (test2) s)
+ ;; change cipher spec
+ ;; multiple handshake messages
+ (finish-output)
+ #+nil
+ (list (next-$Record (rw:byte-reader s)) ;; new session ticket
+ (next-$Record (rw:byte-reader s)) ;; change cipher spec
+ (next-$Record (rw:byte-reader s)) ;; encrypted handshake message
+ )
+ ;; encrypted app data
+ )