Partially modernize algorithm selections

This commit is contained in:
Tony Garnock-Jones 2021-06-14 17:09:35 +02:00
parent b957f81b02
commit 30f395157a
18 changed files with 471 additions and 250 deletions

View File

@ -4,13 +4,13 @@ serverpid=$!
echo "Serverpid is $serverpid"
while true
do
if netstat -an | grep -q '2322.*LISTEN'
if netstat -an | grep -q '29418.*LISTEN'
then
break
fi
sleep 0.1
done
echo '(+ 1 2 3 4 5 6)' | ssh localhost -p 2322
echo '(+ 1 2 3 4 5 6)' | ssh localhost -p 29418
sleep 1
kill -INT $serverpid
echo "Killed $serverpid"

View File

@ -0,0 +1,91 @@
#lang racket/base
;;; SPDX-License-Identifier: LGPL-3.0-or-later
;;; SPDX-FileCopyrightText: Copyright © 2018-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
(require bitsyntax)
(require racket/unix-socket)
(require net/base64)
(define-values (i o) (unix-socket-connect (getenv "SSH_AUTH_SOCK")))
(define SSH_AGENT_FAILURE 5)
(define SSH_AGENT_SUCCESS 6)
(define SSH_AGENTC_REQUEST_IDENTITIES 11)
(define SSH_AGENT_IDENTITIES_ANSWER 12)
(define SSH_AGENTC_SIGN_REQUEST 13)
(define SSH_AGENT_SIGN_RESPONSE 14)
(define SSH_AGENTC_ADD_IDENTITY 17)
(define SSH_AGENTC_REMOVE_IDENTITY 18)
(define SSH_AGENTC_REMOVE_ALL_IDENTITIES 19)
(define SSH_AGENTC_ADD_SMARTCARD_KEY 20)
(define SSH_AGENTC_REMOVE_SMARTCARD_KEY 21)
(define SSH_AGENTC_LOCK 22)
(define SSH_AGENTC_UNLOCK 23)
(define SSH_AGENTC_ADD_ID_CONSTRAINED 25)
(define SSH_AGENTC_ADD_SMARTCARD_KEY_CONSTRAINED 26)
(define SSH_AGENTC_EXTENSION 27)
(define SSH_AGENT_EXTENSION_FAILURE 28)
(struct identity (blob comment) #:transparent)
(define (write-packet o type bs)
(write-bytes (bit-string->bytes
(bit-string ((+ 1 (bytes-length bs)) :: bits 32)
(type :: bits 8)
(bs :: binary)))
o)
(flush-output o))
(define (read-packet i)
(bit-string-case (read-bytes 4 i)
([(len :: bits 32)]
(bit-string-case (read-bytes len i)
([(type :: bits 8) (body :: binary)]
(values type body))))))
(define (list-keys i o)
(write-packet o SSH_AGENTC_REQUEST_IDENTITIES #"")
(define-values (response-type body) (read-packet i))
(when (not (= response-type SSH_AGENT_IDENTITIES_ANSWER))
(error 'list-keys "Invalid response from SSH agent: ~a" response-type))
(bit-string-case body
([ (nkeys :: bits 32) (body :: binary) ]
(let loop ((acc-rev '()) (nkeys nkeys) (body body))
(if (zero? nkeys)
(reverse acc-rev)
(bit-string-case body
([ (bloblen :: bits 32) (blob :: binary bytes bloblen)
(commentlen :: bits 32) (comment :: binary bytes commentlen)
(rest :: binary) ]
(loop (cons (identity (bit-string->bytes blob)
(bytes->string/utf-8 (bit-string->bytes comment)))
acc-rev)
(- nkeys 1)
rest))))))))
(define (blob-ed25519-key blob)
(bit-string-case blob
([ (= 11 :: bits 32) (= #"ssh-ed25519" :: binary bytes 11)
(= 32 :: bits 32) (pk :: binary bytes 32) ]
(bit-string->bytes pk))
(else #f)))
(define (sign data id i o)
(write-packet o SSH_AGENTC_SIGN_REQUEST
(bit-string->bytes
(bit-string ((bytes-length (identity-blob id)) :: bits 32)
((identity-blob id) :: binary)
((bytes-length data) :: bits 32)
(data :: binary)
(0 :: bits 32))))
(define-values (response-type body) (read-packet i))
(when (not (= response-type SSH_AGENT_SIGN_RESPONSE))
(error 'sign "Invalid response from SSH agent: ~a" response-type))
(bit-string-case body
([ (len :: bits 32) (signature :: binary bytes len) ]
(bit-string->bytes signature))))
(let ((ids (filter (lambda (i) (blob-ed25519-key (identity-blob i))) (list-keys i o))))
(for-each writeln ids)
(newline)
)

View File

@ -0,0 +1,110 @@
#lang racket/base
;;; SPDX-License-Identifier: LGPL-3.0-or-later
;;; SPDX-FileCopyrightText: Copyright © 2018-2021 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
(provide file->ssh-private-key
bytes->ssh-private-key)
(require racket/match)
(require (only-in racket/file file->bytes))
(require (only-in racket/port call-with-input-bytes))
(require (only-in racket/string string-join))
(require net/base64)
(require bitsyntax)
;; (require blowfish/bcrypt-hash)
(require crypto)
(require "../ssh-message-types.rkt")
(define (file->ssh-private-key filename [passphrase-bytes #f])
(bytes->ssh-private-key (file->bytes filename) passphrase-bytes))
(define (bytes->ssh-private-key bs [passphrase-bytes #f])
(call-with-input-bytes
bs
(lambda (p)
(and (equal? (read-line p) "-----BEGIN OPENSSH PRIVATE KEY-----")
(let ((blob (let collect ((acc '()))
(match (read-line p)
["-----END OPENSSH PRIVATE KEY-----"
(base64-decode (string->bytes/latin-1 (string-join (reverse acc))))]
[line
(collect (cons line acc))]))))
(bit-string-case blob
([ (= #"openssh-key-v1\0" :: binary bytes 15)
(ciphername :: (t:string #:pack))
(kdfname :: (t:string #:pack))
(kdfoptions :: (t:string #:pack))
(= 1 :: bits 32) ;; OpenSSH only supports one key
(public-keys :: (t:repeat 1 (t:string #:pack)))
(private-keys :: (t:string #:pack)) ]
(decode-private-keys passphrase-bytes
ciphername
kdfname
kdfoptions
(car public-keys)
private-keys))
(else #f)))))))
(define (decode-private-keys passphrase-bytes
ciphername
kdfname
kdfoptions
public-key
private-keys)
(define pk-bytes
(bit-string-case public-key
([ (= #"ssh-ed25519" :: (t:string #:pack))
(bs :: (t:string #:pack)) ]
bs)))
(define (decode-decrypted blob)
;; Oddly, this only partially lines up with the spec at
;; https://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL.key?annotate=1.1
;;
;; Specifically, contra spec, after the checkints, we seem to have
;; the public key again followed by the private key bytes and then
;; a comment string.
;;
;; The code (sshkey.c) does this:
;; - retrieve a key type string
;; - dispatch on it
;; - for ed25519, read a string with the PK, then a string with the SK
;; - checks the sizes to ensure they are correct for ed25519
;;
;; This is what the PROTOCOL.key documentation says to do. It's
;; not what actually needs to be done.
;;
;; [ (checkint1 :: bits 32) (= checkint1 :: bits 32) ;; must be the same
;; (keys :: (t:repeat 1 (t:repeat 2 (t:string #:pack))))
;; (= 'padding-ok :: (t:padding)) ]
;;
(bit-string-case blob
([ (checkint1 :: bits 32) (= checkint1 :: bits 32) ;; must be the same
(= #"ssh-ed25519" :: (t:string #:pack))
(pk-bytes-in-sk :: (t:string #:pack))
(sk :: (t:string #:pack))
(comment :: (t:string #:pack))
(= 'padding-ok :: (t:padding))
]
(and (equal? pk-bytes pk-bytes-in-sk)
(list pk-bytes sk (bytes->string/utf-8 comment))))
(else #f)))
(match* (ciphername kdfname)
[(#"none" #"none")
(decode-decrypted private-keys)]
;; This stanza works, I just don't want to depend on bcrypt just yet:
#;[(#"aes256-ctr" #"bcrypt")
(define keylen (/ 256 8)) ;; aes256 = 256 bit key length
(define ivlen (/ 128 8)) ;; fixed block size of 128 bits
(bit-string-case kdfoptions
([ (salt :: (t:string #:pack))
(rounds :: bits 32) ]
(when (not passphrase-bytes) (error 'read-ssh-private-key "Passphrase required"))
(bit-string-case (bcrypt-pbkdf passphrase-bytes salt (+ keylen ivlen) rounds)
([ (key :: binary bytes keylen) (iv :: binary bytes ivlen) ]
(decode-decrypted
(parameterize ((crypto-factories (list libcrypto-factory)))
(decrypt '(aes ctr) (bit-string->bytes key) (bit-string->bytes iv) private-keys)))))))]
[(_ _)
(error 'read-ssh-private-key "Unsupported private-key cipher/kdf")]))

View File

@ -25,7 +25,7 @@
(spawn-tcp-driver ds)
(spawn #:name 'ssh-tcp-listener
(at ds
(during/spawn (Connection $conn (TcpInbound "0.0.0.0" 2322))
(during/spawn (Connection $conn (TcpInbound "0.0.0.0" 29418))
#:name (list 'ssh conn)
(session ds conn))))))
@ -50,7 +50,7 @@
#:initial-credit #f
#:on-data (lambda (input mode) (error 'session "Unexpected input"))))
(define local-identification "SSH-2.0-RacketSSH_0.0")
(define local-identification #"SSH-2.0-RacketSSH_0.0")
(send-line conn local-identification)
(send-lines-credit conn 1 (LineMode-crlf))
@ -87,9 +87,9 @@
'server)))))
(at conn-ds
(during $m
(on-start (log-info "++ ~v" m))
(on-stop (log-info "-- ~v" m)))
;; (during $m
;; (on-start (log-info "++ ~v" m))
;; (on-stop (log-info "-- ~v" m)))
(when (message $m)
(log-info ">> ~v" m)))

View File

@ -8,15 +8,13 @@
(require bitsyntax)
(require "crypto.rkt")
(require "asn1-ber.rkt")
(require "keys/ssh-keys.rkt")
(require "ssh-message-types.rkt")
(require rackunit)
(provide (struct-out rsa-private-key)
(struct-out dsa-private-key)
(struct-out rsa-public-key)
(struct-out dsa-public-key)
(provide (struct-out ed25519-private-key)
(struct-out ed25519-public-key)
public-key->pieces
pieces->public-key
@ -28,153 +26,77 @@
pieces->ssh-host-key
ssh-host-key->pieces)
(struct rsa-private-key (version n e d p q dmp1 dmq1 iqmp) #:transparent)
(struct dsa-private-key (version p q g y x) #:transparent)
(struct rsa-public-key (n e) #:transparent)
(struct dsa-public-key (y p q g) #:transparent)
;; ASN.1 BER integers are signed.
(define (bs->n bs) (bit-string->integer bs #t #t))
(define (n->bs n) (integer->bit-string n (* 8 (mpint-width n)) #t))
;; (define (private-key->pieces key)
;; (bytes->private-key-pieces (private-key->bytes key)))
(struct ed25519-private-key (q d) #:transparent)
(struct ed25519-public-key (q) #:transparent)
(define (bytes->private-key-pieces bs)
(match (asn1-ber-decode-all bs)
(`(0 16 ((0 2 ,version-bytes)
(0 2 ,n-bytes)
(0 2 ,e-bytes)
(0 2 ,d-bytes)
(0 2 ,p-bytes)
(0 2 ,q-bytes)
(0 2 ,dmp1-bytes)
(0 2 ,dmq1-bytes)
(0 2 ,iqmp-bytes)))
(rsa-private-key (bs->n version-bytes)
(bs->n n-bytes)
(bs->n e-bytes)
(bs->n d-bytes)
(bs->n p-bytes)
(bs->n q-bytes)
(bs->n dmp1-bytes)
(bs->n dmq1-bytes)
(bs->n iqmp-bytes)))
(`(0 16 ((0 2 ,version-bytes)
(0 2 ,p-bytes)
(0 2 ,q-bytes)
(0 2 ,g-bytes)
(0 2 ,public-key-bytes) ;; y
(0 2 ,private-key-bytes))) ;; x
(dsa-private-key (bs->n version-bytes)
(bs->n p-bytes)
(bs->n q-bytes)
(bs->n g-bytes)
(bs->n public-key-bytes)
(bs->n private-key-bytes)))))
(match (bytes->ssh-private-key bs)
[(list pk-bytes sk-bytes _comment)
(ed25519-private-key pk-bytes sk-bytes)]))
(define (pieces->private-key p)
(match p
[(struct rsa-private-key (version n e d _p _q _dmp1 _dmq1 _iqmp))
(datum->pk-key (list 'rsa 'private n e d)
'rkt-private)]
[(struct dsa-private-key (version p q g y x))
(datum->pk-key (list 'dsa 'private p q g y x)
'rkt-private)]))
[(ed25519-private-key q d)
(datum->pk-key (list 'eddsa 'private 'ed25519 q d) 'rkt-private)]))
(define (public-key->pieces key)
(match (pk-key->datum key 'rkt-public)
[(list 'rsa 'public n e)
(rsa-public-key n e)]
[(list 'dsa 'public p q g public-key-bytes)
(dsa-public-key public-key-bytes p q g)]))
[(list 'eddsa 'public 'ed25519 q)
(ed25519-public-key q)]))
(define (pieces->public-key p)
(match p
((struct rsa-public-key (n e))
(datum->pk-key (list 'rsa 'public n e) 'rkt-public))
((struct dsa-public-key (y p q g))
(datum->pk-key (list 'dsa 'public p q g y) 'rkt-public))))
[(ed25519-public-key q)
(datum->pk-key (list 'eddsa 'public 'ed25519 q) 'rkt-public)]))
(define (host-key-algorithm->keys host-key-alg)
(case host-key-alg
((ssh-dss) (values host-key-dsa-private host-key-dsa-public))
((ssh-ed25519) (values host-key-ed25519-private host-key-ed25519-public))
(else (error 'host-key-algorithm->keys "Unsupported host-key-alg ~v" host-key-alg))))
(define (host-key-signature private-key host-key-alg exchange-hash)
(case host-key-alg
((ssh-rsa)
;; TODO: offer ssh-rsa. See comment in definition of
;; local-algorithm-list in ssh-transport.rkt.
(error 'host-key-signature "ssh-rsa host key signatures unimplemented"))
((ssh-dss)
(match (asn1-ber-decode-all (pk-sign private-key exchange-hash))
(`(0 16 ((0 2 ,r-bytes)
(0 2 ,s-bytes)))
(bit-string (#"ssh-dss" :: (t:string))
((bit-string ((bs->n r-bytes) :: big-endian integer bits 160)
((bs->n s-bytes) :: big-endian integer bits 160))
:: (t:string))))))))
[(ssh-ed25519)
(define signature (pk-sign private-key exchange-hash))
(log-info "signature length ~a value ~v verifies"
(bytes-length signature)
signature)
(bit-string (#"ssh-ed25519" :: (t:string))
(signature :: (t:string)))]))
(define (verify-host-key-signature! public-key host-key-alg exchange-hash h-signature)
;; TODO: If we are *re*keying, worth checking here that the key hasn't *changed* either.
(write `(TODO check-host-key!)) (newline) (flush-output) ;; actually check the identity TOFU/POP
(case host-key-alg
((ssh-rsa)
;; TODO: offer ssh-rsa. See comment in definition of
;; local-algorithm-list in ssh-transport.rkt.
(error 'verify-host-key-signature! "ssh-rsa host key signatures unimplemented"))
((ssh-dss)
[(ssh-ed25519)
(define signature (bit-string-case h-signature
([ (= #"ssh-dss" :: (t:string #:pack))
(r-and-s :: (t:string)) ]
(bit-string-case r-and-s
([ (r :: big-endian integer bits 160)
(s :: big-endian integer bits 160) ]
(asn1-ber-encode `(0 16 ((0 2 ,(n->bs r))
(0 2 ,(n->bs s))))))))))
([ (= #"ssh-ed25519" :: (t:string #:pack))
(sig :: (t:string #:pack)) ]
sig)))
(when (not (pk-verify public-key exchange-hash signature))
(error 'verify-host-key-signature! "Signature mismatch")))))
(error 'verify-host-key-signature! "Signature mismatch"))]))
(define (pieces->ssh-host-key pieces)
(match pieces
((struct rsa-public-key (n e))
(bit-string (#"ssh-rsa" :: (t:string))
(e :: (t:mpint))
(n :: (t:mpint))))
((struct dsa-public-key (y p q g))
(bit-string (#"ssh-dss" :: (t:string))
(p :: (t:mpint))
(q :: (t:mpint))
(g :: (t:mpint))
(y :: (t:mpint))))))
[(ed25519-public-key q)
(bit-string (#"ssh-ed25519" :: (t:string))
(q :: (t:string)))]))
(define (ssh-host-key->pieces blob)
(bit-string-case blob
([ (= #"ssh-rsa" :: (t:string #:pack))
(e :: (t:mpint))
(n :: (t:mpint)) ]
(rsa-public-key n e))
([ (= #"ssh-dss" :: (t:string #:pack))
(p :: (t:mpint))
(q :: (t:mpint))
(g :: (t:mpint))
(y :: (t:mpint)) ]
(dsa-public-key y p q g))))
([ (= #"ssh-ed25519" :: (t:string #:pack))
(q :: (t:string #:pack)) ]
(ed25519-public-key q))))
;; TODO: proper store for keys
(define (load-private-key filename)
(pieces->private-key
(bytes->private-key-pieces
(base64-decode
(regexp-replace* #rx"(?m:^-.*-$)"
(call-with-input-file filename port->bytes)
#"")))))
(local-require (only-in racket/file file->bytes))
(pieces->private-key (bytes->private-key-pieces (file->bytes filename))))
(define host-key-dsa-private (load-private-key "test-dsa-key"))
(define host-key-dsa-public (pk-key->public-only-key host-key-dsa-private))
(define host-key-ed25519-private (load-private-key "test-host-keys/ssh_host_ed25519_key"))
(define host-key-ed25519-public (pk-key->public-only-key host-key-ed25519-private))
(check-equal? (pk-key->datum (pieces->public-key (public-key->pieces host-key-dsa-public))
(check-equal? (pk-key->datum (pieces->public-key (public-key->pieces host-key-ed25519-public))
'SubjectPublicKeyInfo)
(pk-key->datum host-key-dsa-private 'SubjectPublicKeyInfo))
(pk-key->datum host-key-ed25519-private 'SubjectPublicKeyInfo))

View File

@ -20,7 +20,9 @@
t:string
t:mpint
mpint-width
t:name-list)
t:name-list
t:repeat
t:padding)
(provide (struct-out ssh-msg-kexinit)
(struct-out ssh-msg-kexdh-init)
@ -135,6 +137,35 @@
((_ #f ns)
(t:string #f (symbols->name-list ns)))))
(define-syntax t:repeat
(syntax-rules ()
[(_ #t input ks kf parser)
(let loop ((acc-rev '()) (rest input))
(bit-string-case rest
([ (item :: parser) (rest :: binary) ] (loop (cons item acc-rev) rest))
(else (ks (reverse acc-rev) rest))))]
[(_ #t input ks kf ntimes parser)
(let loop ((acc-rev '()) (rest input) (n ntimes))
(if (zero? n)
(ks (reverse acc-rev) rest)
(bit-string-case rest
([ (item :: parser) (rest :: binary) ]
(loop (cons item acc-rev) rest (- n 1))))))]
[(_ #f items0 parser)
(let loop ((items items0))
(match items
['() #""]
[(cons item items) (bit-string (item :: parser) (loop items))]))]))
(define-syntax t:padding
(syntax-rules ()
[(_ #t input ks kf)
(let loop ((expected 1) (rest input))
(bit-string-case rest
([ (= expected) (rest :: binary) ] (loop (+ expected 1) rest))
([ ] (ks 'padding-ok #""))
(else (kf))))]))
(define-for-syntax (codec-options field-type)
(syntax-case field-type (byte boolean uint32 uint64 string mpint name-list)
(byte #'(integer bits 8))

View File

@ -302,6 +302,7 @@
;; ------------ ---------
diffie-hellman-group1-sha1 ;[SSH-TRANS, Section 8.1]
diffie-hellman-group14-sha1 ;[SSH-TRANS, Section 8.2]
diffie-hellman-group14-sha256 ;; RFC8268 section 5
))
;; The following table identifies the initial assignment of the
@ -357,6 +358,10 @@
hmac-md5 ;[SSH-TRANS, Section 6.4]
hmac-md5-96 ;[SSH-TRANS, Section 6.4]
none ;[SSH-TRANS, Section 6.4]
hmac-sha2-256 ;; RFC6668 Section 2
hmac-sha2-512 ;; RFC6668 Section 2
))
;; The following table identifies the initial assignments of the Public
@ -368,6 +373,9 @@
ssh-rsa ;[SSH-TRANS, Section 6.6]
pgp-sign-rsa ;[SSH-TRANS, Section 6.6]
pgp-sign-dss ;[SSH-TRANS, Section 6.6]
ssh-ed25519 ;; RFC8709 section 3
ssh-ed448 ;; RFC8709 section 3
))
;; The following table identifies the initial assignments of the

View File

@ -63,12 +63,11 @@
;; Packet dispatch and handling
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; (task Nat Bytes SshMsg)
;; (task-accepted Nat)
;; Message handlers subscribe to `task`s, and assert `task-accepted` in reply.
;; If they do not timely assert `task-accepted`, SSH_MSG_UNIMPLEMENTED is generated.
(struct task (seq packet message) #:prefab)
(struct task-accepted (seq) #:prefab)
;; (task Nat Byte Bytes SshMsg)
;; (task-complete Nat)
;; Message handlers respond to `task` messages, eventually sending `task-complete`.
(struct task (seq packet-type packet message) #:prefab)
(struct task-complete (seq) #:prefab)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Key Exchange
@ -97,9 +96,9 @@
((memq (car client-list) server-list) (car client-list))
(else (loop (cdr client-list))))))
;; ExchangeHashInfo Bytes Natural Natural Natural -> Bytes
;; HashFunction ExchangeHashInfo Bytes Natural Natural Natural -> Bytes
;; Computes the session ID as defined by SSH's DH key exchange method.
(define (dh-exchange-hash hash-info host-key e f k)
(define (dh-exchange-hash hash-alg hash-info host-key e f k)
(let ((block-to-hash
(bit-string->bytes
(bit-string ((exchange-hash-info-client-id hash-info) :: (t:string))
@ -110,45 +109,40 @@
(e :: (t:mpint))
(f :: (t:mpint))
(k :: (t:mpint))))))
(sha1 block-to-hash)))
(hash-alg block-to-hash)))
;; DS ExchangeHashInfo Symbol Symbol (Bytes Bytes Symbol -> Void) -> Void
;; Performs the server's half of the Diffie-Hellman key exchange protocol.
(define (perform-server-key-exchange conn-ds hash-info kex-alg host-key-alg finish)
(match kex-alg
[(or 'diffie-hellman-group14-sha1 'diffie-hellman-group1-sha1)
(define group (if (eq? kex-alg 'diffie-hellman-group14-sha1)
dh:oakley-group-14
dh:oakley-group-2)) ;; yes, SSH's group1 == Oakley/RFC2409 group 2
['diffie-hellman-group14-sha256
(define group dh:oakley-group-14)
(define private-key (generate-private-key group))
(match-define (list 'dh 'public _p _g public-key-as-integer)
(match-define (list 'dh 'public p g public-key-as-integer)
(pk-key->datum private-key 'rkt-public))
(react
(at conn-ds
(during (task $seq _ (ssh-msg-kexdh-init $e))
(at conn-ds (assert (task-accepted seq)))
(on-start (define e-width (mpint-width e))
(define e-as-bytes (integer->bit-string e (* 8 e-width) #t))
(define shared-secret (pk-derive-secret private-key e-as-bytes))
(define hash-alg sha1)
(define-values (host-key-private host-key-public)
(host-key-algorithm->keys host-key-alg))
(define host-key-bytes
(pieces->ssh-host-key (public-key->pieces host-key-public)))
(define exchange-hash
(dh-exchange-hash hash-info
host-key-bytes
e
public-key-as-integer
(bit-string->integer shared-secret #t #f)))
(define h-signature (host-key-signature host-key-private
host-key-alg
exchange-hash))
(send! conn-ds (outbound-packet
(ssh-msg-kexdh-reply (bit-string->bytes host-key-bytes)
public-key-as-integer
(bit-string->bytes h-signature))))
(finish shared-secret exchange-hash hash-alg)))))]
(when (message (task $seq SSH_MSG_KEXDH_INIT _ (ssh-msg-kexdh-init $e)))
(define peer-key (datum->pk-key (list 'dh 'public p g e) 'rkt-public))
(define shared-secret (pk-derive-secret private-key peer-key))
(define hash-alg sha256)
(define-values (host-key-private host-key-public)
(host-key-algorithm->keys host-key-alg))
(define host-key-bytes (pieces->ssh-host-key (public-key->pieces host-key-public)))
(define exchange-hash (dh-exchange-hash hash-alg
hash-info
host-key-bytes
e
public-key-as-integer
(bit-string->integer shared-secret #t #f)))
(define h-signature (host-key-signature host-key-private host-key-alg exchange-hash))
(log-info "h-signature ~v public-key-as-integer ~v" h-signature public-key-as-integer)
(send! conn-ds (outbound-packet
(ssh-msg-kexdh-reply (bit-string->bytes host-key-bytes)
public-key-as-integer
(bit-string->bytes h-signature))))
(send! conn-ds (task-complete seq))
(finish shared-secret exchange-hash hash-alg))))]
[_ (disconnect-with-error conn-ds SSH_DISCONNECT_KEY_EXCHANGE_FAILED
"Bad key-exchange algorithm ~v" kex-alg)]))
@ -156,35 +150,29 @@
;; Performs the client's half of the Diffie-Hellman key exchange protocol.
(define (perform-client-key-exchange conn-ds hash-info kex-alg host-key-alg finish)
(match kex-alg
[(or 'diffie-hellman-group14-sha1 'diffie-hellman-group1-sha1)
(define group (if (eq? kex-alg 'diffie-hellman-group14-sha1)
dh:oakley-group-14
dh:oakley-group-2)) ;; yes, SSH's group1 == Oakley/RFC2409 group 2
['diffie-hellman-group14-sha256
(define group dh:oakley-group-14)
(define private-key (generate-private-key group))
(match-define (list 'dh 'public _p _g public-key-as-integer)
(match-define (list 'dh 'public p g public-key-as-integer)
(pk-key->datum private-key 'rkt-public))
(send! conn-ds (outbound-packet (ssh-msg-kexdh-init public-key-as-integer)))
(react
(at conn-ds
(during (task $seq _ (ssh-msg-kexdh-reply $host-key-bytes $f $h-signature))
(at conn-ds (assert (task-accepted seq)))
(on-start (define f-width (mpint-width f))
(define f-as-bytes (integer->bit-string f (* 8 f-width) #t))
(define shared-secret (pk-derive-secret private-key f-as-bytes))
(define hash-alg sha1)
(define host-public-key
(pieces->public-key (ssh-host-key->pieces host-key-bytes)))
(define exchange-hash
(dh-exchange-hash hash-info
host-key-bytes
public-key-as-integer
f
(bit-string->integer shared-secret #t #f)))
(verify-host-key-signature! host-public-key
host-key-alg
exchange-hash
h-signature)
(finish shared-secret exchange-hash hash-alg)))))]
(when (message (task $seq SSH_MSG_KEXDH_REPLY _
(ssh-msg-kexdh-reply $host-key-bytes $f $h-signature)))
(define peer-key (datum->pk-key (list 'dh 'public p g f) 'rkt-public))
(define shared-secret (pk-derive-secret private-key peer-key))
(define hash-alg sha256)
(define host-public-key (pieces->public-key (ssh-host-key->pieces host-key-bytes)))
(define exchange-hash (dh-exchange-hash hash-alg
hash-info
host-key-bytes
public-key-as-integer
f
(bit-string->integer shared-secret #t #f)))
(verify-host-key-signature! host-public-key host-key-alg exchange-hash h-signature)
(send! conn-ds (task-complete seq))
(finish shared-secret exchange-hash hash-alg))))]
[_ (disconnect-with-error conn-ds SSH_DISCONNECT_KEY_EXCHANGE_FAILED
"Bad key-exchange algorithm ~v" kex-alg)]))
@ -280,8 +268,7 @@
(key :: binary))))))))))
(react
(at conn-ds
(during (task $seq _ (ssh-msg-newkeys))
(at conn-ds (assert (task-accepted seq)))
(when (message (task $seq SSH_MSG_NEWKEYS _ (ssh-msg-newkeys)))
;; First, send our SSH_MSG_NEWKEYS, incrementing the
;; various counters, and then apply the new algorithms.
;; Also arm our rekey timer.
@ -291,13 +278,14 @@
(send! conn-ds 'enable-service-request!)
(send! conn-ds (outbound-packet (ssh-msg-newkeys)))
(send! conn-ds (new-keys is-server?
derive-key
(embedded derive-key)
c2s-enc s2c-enc
c2s-mac s2c-mac
c2s-zip s2c-zip))
(send! ground-ds (SetTimer 'rekey-timer
(* (rekey-wait-deadline (rekey-state)) 1000)
(TimerKind-absolute)))))))))
(TimerKind-absolute)))
(send! conn-ds (task-complete seq))))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Service request manager
@ -691,32 +679,33 @@
(define is-server? (case session-role ((client) #f) ((server) #t)))
(at conn-ds
(during (task $seq _ (ssh-msg-disconnect $reason-code $description $language-tag))
(at conn-ds (assert (task-accepted seq)))
(when (message (task $seq SSH_MSG_DISCONNECT _
(ssh-msg-disconnect $reason-code $description $language-tag)))
(disconnect-with-error* conn-ds #t
'()
reason-code
"Received SSH_MSG_DISCONNECT with reason code ~a and message ~s"
reason-code
(bytes->string/utf-8 (bit-string->bytes description))))
(bytes->string/utf-8 (bit-string->bytes description)))
(send! conn-ds (task-complete seq)))
(during (task $seq _ (ssh-msg-ignore _))
(at conn-ds (assert (task-accepted seq))))
(when (message (task $seq SSH_MSG_IGNORE _ (ssh-msg-ignore _)))
(send! conn-ds (task-complete seq)))
(during (task $seq _ (ssh-msg-unimplemented $peer-seq))
(at conn-ds (assert (task-accepted seq)))
(when (message (task $seq SSH_MSG_UNIMPLEMENTED _ (ssh-msg-unimplemented $peer-seq)))
(disconnect-with-error/local-info
conn-ds
`((offending-sequence-number ,peer-seq))
SSH_DISCONNECT_PROTOCOL_ERROR
"Disconnecting because of received SSH_MSG_UNIMPLEMENTED."))
"Disconnecting because of received SSH_MSG_UNIMPLEMENTED.")
(send! conn-ds (task-complete seq)))
(during (task $seq _ ($ message (ssh-msg-debug _ _ _)))
(at conn-ds (assert (task-accepted seq)))
(log-info (format "Received SSHv2 SSH_MSG_DEBUG packet ~v" message)))
(when (message (task $seq SSH_MSG_DEBUG _ ($ message (ssh-msg-debug _ _ _))))
(log-info (format "Received SSHv2 SSH_MSG_DEBUG packet ~v" message))
(send! conn-ds (task-complete seq)))
(during (task $seq $packet ($ message (ssh-msg-kexinit _ _ _ _ _ _ _ _ _ _ _ _ _)))
(at conn-ds (assert (task-accepted seq)))
(when (message (task $seq SSH_MSG_KEXINIT $packet
($ message (ssh-msg-kexinit _ _ _ _ _ _ _ _ _ _ _ _ _))))
(do-kexinit conn-ds
ground-ds
#:packet packet
@ -727,7 +716,8 @@
#:remote-id peer-identification-string
#:session-id session-id
#:total-transferred total-transferred
#:discard-next-packet? discard-next-packet?))
#:discard-next-packet? discard-next-packet?)
(send! conn-ds (task-complete seq)))
(when (message 'enable-service-request!)
(log-info "Saw enable-service-request!")
@ -759,7 +749,8 @@
(when (message (inbound-packet $sequence-number $payload $message $transfer-size))
(if (discard-next-packet?)
(discard-next-packet? #f)
(begin (discard-next-packet? #f)
(send! conn-ds (inbound-credit 1)))
(let ((packet-type-number (bytes-ref payload 0)))
(if (and (not (rekey-wait? (rekey-state)))
(or (not (ssh-msg-type-transport-layer? packet-type-number))
@ -773,13 +764,19 @@
"Packets of type ~v forbidden while in key-exchange"
packet-type-number)
;; We're either idling, or it's a permitted packet type while
;; performing key exchange. Look it up in the dispatch table.
;; performing key exchange. Dispatch it.
(react
(at conn-ds
(assert (task sequence-number payload message))
(stop-when (asserted (task-accepted sequence-number))))
(sync! conn-ds
(send! conn-ds (outbound-packet (ssh-msg-unimplemented sequence-number))))))))
(on-start
(send! conn-ds (task sequence-number packet-type-number payload message)))
(let ((handler-present #f))
(at conn-ds
(when (asserted (Observe (:pattern (task ,_ packet-type-number ,_ ,_)) _))
(set! handler-present #t)))
(sync! conn-ds
(when (not handler-present)
(send! conn-ds (outbound-packet (ssh-msg-unimplemented sequence-number)))
(send! conn-ds (task-complete sequence-number)))))
(at conn-ds (stop-when (message (task-complete sequence-number))))
(on-stop (send! conn-ds (inbound-credit 1)))))))
(total-transferred (+ (total-transferred) transfer-size))
(send! conn-ds (inbound-credit 1))
(maybe-rekey))))

View File

@ -96,22 +96,24 @@
0
0))
(define (make-cipher-entry name cipher-spec key-length)
(define (make-cipher-entry name cipher-spec key-length
#:block-size [block-size (cipher-block-size cipher-spec)])
(list name
(supported-cipher name
(lambda (enc? key iv)
(lambda (input)
((if enc? encrypt decrypt)
cipher-spec key iv input #:pad #f)))
(let ((ctx ((if enc? make-encrypt-ctx make-decrypt-ctx)
cipher-spec key iv #:pad #f)))
(lambda (input)
(cipher-update ctx input))))
key-length
(cipher-block-size cipher-spec)
block-size
(cipher-iv-size cipher-spec))))
(define supported-crypto-algorithms
(list
(make-cipher-entry 'aes128-ctr '(aes ctr) 16)
(make-cipher-entry 'aes192-ctr '(aes ctr) 24)
(make-cipher-entry 'aes256-ctr '(aes ctr) 32)
(make-cipher-entry 'aes128-ctr '(aes ctr) 16 #:block-size 16)
(make-cipher-entry 'aes192-ctr '(aes ctr) 24 #:block-size 16)
(make-cipher-entry 'aes256-ctr '(aes ctr) 32 #:block-size 16)
(make-cipher-entry 'aes128-cbc '(aes cbc) 16)
(make-cipher-entry 'aes192-cbc '(aes cbc) 24)
(make-cipher-entry 'aes256-cbc '(aes cbc) 32)
@ -130,8 +132,7 @@
key-length))))
(define supported-hmac-algorithms
(list (make-hmac-entry 'hmac-md5 'md5 #f)
(make-hmac-entry 'hmac-sha1 'sha1 #f)))
(list (make-hmac-entry 'hmac-sha1 'sha1 #f)))
(define supported-compression-algorithms '(none)) ;; TODO: zlib, and zlib delayed
@ -141,13 +142,8 @@
(make-parameter
(lambda ()
(ssh-msg-kexinit (crypto-random-bytes 16)
'(diffie-hellman-group14-sha1
diffie-hellman-group1-sha1)
'(ssh-dss) ;; TODO: offer ssh-rsa. This will
;; involve replicating the tedious
;; crypto operations from the spec
;; rather than being able to use
;; the builtins from OpenSSL.
'(diffie-hellman-group14-sha256)
'(ssh-ed25519)
crypto-names
crypto-names
mac-names
@ -171,7 +167,7 @@
(define (apply-negotiated-options conn-ds nk is-outbound?)
(match-define (new-keys is-server?
derive-key
(embedded derive-key)
c2s-enc s2c-enc
c2s-mac s2c-mac
c2s-zip s2c-zip) nk)
@ -284,8 +280,6 @@
(define first-block (decrypt-chunk encrypted-packet))
(define packet-length (integer-bytes->integer first-block #f #t 0 4))
(check-packet-length! conn-ds packet-length packet-size-limit (subsequent-block-size))
(define padding-length (bytes-ref first-block 4))
(define payload-length (- packet-length padding-length 1))
(define amount-of-packet-in-first-block (- (bytes-length first-block) 4)) ;; not incl length
(define remaining-to-read (- packet-length amount-of-packet-in-first-block))
(if (positive? remaining-to-read)
@ -293,12 +287,13 @@
(send-bytes-credit conn remaining-to-read)
(update-input-handler
#:on-data (lambda (encrypted-packet _mode)
(check-hmac packet-length
payload-length
(bytes-append first-block (decrypt-chunk encrypted-packet))))))
(check-hmac packet-length payload-length first-block)))
(check-hmac (bytes-append first-block (decrypt-chunk encrypted-packet))
packet-length))))
(check-hmac first-block packet-length)))
(define (check-hmac packet-length payload-length packet)
(define (check-hmac packet packet-length)
(define payload-length (let ((padding-length (bytes-ref packet 4)))
(- packet-length padding-length 1)))
(define computed-hmac-bytes (apply-hmac (hmac) sequence-number packet))
(define mac-byte-count (bytes-length computed-hmac-bytes))
(if (positive? mac-byte-count)

View File

@ -1,12 +0,0 @@
-----BEGIN DSA PRIVATE KEY-----
MIIBuwIBAAKBgQCEQ1YvOR7/MQByCPJt/FSO7NN7YO1VLqy7A95M07q6AaG5FZ2A
m9s8KZPlNFPrNhG8pRxxHhWgfBczoIObZi2saXeXQyTCUtHUejQBk+Xl31I+0SYU
/m5fIP3Q9UY3cR8LucsIQkJIcuLVpoMmtFA/EtxYs+roxm+wtMlgk/8HkQIVAObN
DEIjvgKwW9MKzRz8VXms/aDDAoGAeMnKQxj/iBSfQ3Wsd4ipCi3PdoLJ0+TJuiFG
0tmbxLxwC0YCR24YMeobva/SpSu6y48+2rjv9Wc9ZKwISbrdO6xrNgDJtoCZLGK+
C2DHEC3rBYFicOgpoysk/HsS/to3GtMnPyA2NJDR/cjUdgWBRg+4eAx1ZsVPjaJT
A5Z60tECgYAkhzk5oi/b3zxPEPoFYki2apR4mciJso/1mYvb6fpd+rzlihNrkFAA
LL+6uOofkyf32FIQhEN+JXDNMfaHreJkLPxGXIJ4FyUbrrZcxbmgJdh9NHd0L/mI
yIHlo+SImp1DLCEtRP1GwKv8Lm0/rFNpY/z5Os3qeXKw1swDvEMfywIVANtH4mhn
F6JfX/4/cJ4cpGlcgrWe
-----END DSA PRIVATE KEY-----

View File

@ -0,0 +1,21 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAABsQAAAAdzc2gtZH
NzAAAAgQCmKbQ9aCROeTmgoNw7/2iajqqMii8GY57HzBNMPv5qkhpK/C3FPRZ4kI8ZWoBd
y24YGjowMe8mi2cLr3Gh92tQxXkgj2PKvS+ciuLJc9wZNkWlb8EGMSObZS37vsY+4QQ+i3
Bzl8/NaKcRm3fNDzo4bPs4KSv20oW53MHwMTuJQwAAABUA6kkgOVsAp/6YzxsPRVq5s2HR
80cAAACAYawX51aiHeSfbwvRO7aewJJVIZIW/56A3jvn8LQAnLXN7E15fyKf+/0curiDA5
Y/XnnhYVx6fy6+TmTFe29J8Epbf/Du1kMQXuYPitH+bAAO6WV20cFzuDiwalmwGzakA4my
jsNUOKfRi9SVtj9wCcROdTpEd2ZuWZIeCkpN9nwAAACAYjn7aqpWxBrkMEpkFm8mv5q3oC
rDE1WEzOFbdjZCNHv0WCNlWuvSmgxbhOgH16NCkPQpKGeJYC/L3i+nAxqt9OcYMnNP+QOA
U7mMtWIYk6/AWjif4xPbevuqXwjXBNtaJxTM5rx7VgRXTpGknPAnmmr3d8rx4JqiUUZ/9U
ZKhJIAAAHg+nHUbPpx1GwAAAAHc3NoLWRzcwAAAIEApim0PWgkTnk5oKDcO/9omo6qjIov
BmOex8wTTD7+apIaSvwtxT0WeJCPGVqAXctuGBo6MDHvJotnC69xofdrUMV5II9jyr0vnI
riyXPcGTZFpW/BBjEjm2Ut+77GPuEEPotwc5fPzWinEZt3zQ86OGz7OCkr9tKFudzB8DE7
iUMAAAAVAOpJIDlbAKf+mM8bD0VaubNh0fNHAAAAgGGsF+dWoh3kn28L0Tu2nsCSVSGSFv
+egN475/C0AJy1zexNeX8in/v9HLq4gwOWP1554WFcen8uvk5kxXtvSfBKW3/w7tZDEF7m
D4rR/mwADulldtHBc7g4sGpZsBs2pAOJso7DVDin0YvUlbY/cAnETnU6RHdmblmSHgpKTf
Z8AAAAgGI5+2qqVsQa5DBKZBZvJr+at6AqwxNVhMzhW3Y2QjR79FgjZVrr0poMW4ToB9ej
QpD0KShniWAvy94vpwMarfTnGDJzT/kDgFO5jLViGJOvwFo4n+MT23r7ql8I1wTbWicUzO
a8e1YEV06RpJzwJ5pq93fK8eCaolFGf/VGSoSSAAAAFQCA9HN3MB5LBCbMmgC8GaLL6Dvs
swAAAAl0b255Z0B6aXAB
-----END OPENSSH PRIVATE KEY-----

View File

@ -0,0 +1 @@
ssh-dss AAAAB3NzaC1kc3MAAACBAKYptD1oJE55OaCg3Dv/aJqOqoyKLwZjnsfME0w+/mqSGkr8LcU9FniQjxlagF3LbhgaOjAx7yaLZwuvcaH3a1DFeSCPY8q9L5yK4slz3Bk2RaVvwQYxI5tlLfu+xj7hBD6LcHOXz81opxGbd80POjhs+zgpK/bShbncwfAxO4lDAAAAFQDqSSA5WwCn/pjPGw9FWrmzYdHzRwAAAIBhrBfnVqId5J9vC9E7tp7AklUhkhb/noDeO+fwtACctc3sTXl/Ip/7/Ry6uIMDlj9eeeFhXHp/Lr5OZMV7b0nwSlt/8O7WQxBe5g+K0f5sAA7pZXbRwXO4OLBqWbAbNqQDibKOw1Q4p9GL1JW2P3AJxE51OkR3Zm5Zkh4KSk32fAAAAIBiOftqqlbEGuQwSmQWbya/mregKsMTVYTM4Vt2NkI0e/RYI2Va69KaDFuE6AfXo0KQ9CkoZ4lgL8veL6cDGq305xgyc0/5A4BTuYy1YhiTr8BaOJ/jE9t6+6pfCNcE21onFMzmvHtWBFdOkaSc8Ceaavd3yvHgmqJRRn/1RkqEkg== tonyg@zip

View File

@ -0,0 +1,9 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAaAAAABNlY2RzYS
1zaGEyLW5pc3RwMjU2AAAACG5pc3RwMjU2AAAAQQQQh/51Eusyw+QiETwkFKnih14O/P6X
QzaQggoFhLVlU8CEd0rYelEC+PIDthkLLK7FxLFw5hFAFA1nZH0+HX8NAAAAqEsrs/tLK7
P7AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBCH/nUS6zLD5CIR
PCQUqeKHXg78/pdDNpCCCgWEtWVTwIR3Sth6UQL48gO2GQssrsXEsXDmEUAUDWdkfT4dfw
0AAAAgF1PQpFeePfE/wd6/FvykZPd4gYWdf6dKvae487FkMXQAAAAJdG9ueWdAemlwAQID
BAUGBw==
-----END OPENSSH PRIVATE KEY-----

View File

@ -0,0 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBCH/nUS6zLD5CIRPCQUqeKHXg78/pdDNpCCCgWEtWVTwIR3Sth6UQL48gO2GQssrsXEsXDmEUAUDWdkfT4dfw0= tonyg@zip

View File

@ -0,0 +1,7 @@
-----BEGIN OPENSSH PRIVATE KEY-----
b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAAAMwAAAAtzc2gtZW
QyNTUxOQAAACDV6tAG149uzUDypi8xFrtKueqfn4oWtsThNP2CztT92AAAAJCOjer7jo3q
+wAAAAtzc2gtZWQyNTUxOQAAACDV6tAG149uzUDypi8xFrtKueqfn4oWtsThNP2CztT92A
AAAED1wOXdWGc+XwJ0CJOlUOxDnj5ttVnhIgVH7j82nq1HutXq0AbXj27NQPKmLzEWu0q5
6p+fiha2xOE0/YLO1P3YAAAACXRvbnlnQHppcAECAwQ=
-----END OPENSSH PRIVATE KEY-----

View File

@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINXq0AbXj27NQPKmLzEWu0q56p+fiha2xOE0/YLO1P3Y tonyg@zip

View File

@ -0,0 +1,38 @@
-----BEGIN OPENSSH PRIVATE KEY-----
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
agQGul6z+t6Zp5AAAACXRvbnlnQHppcAE=
-----END OPENSSH PRIVATE KEY-----

View File

@ -0,0 +1 @@
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDYRZhy9w3IRr/MTEnIgZau3Uzd+4z+h2wDB2aCfTzUYtXrBt0oYt/WiseLK9XbeIomgtg+a7juYZIJrKEHPDH6CYbGlLYc2eSG+zaZ+ZqQ4/EEepBdi1Pt4R6YzPJuhVwHWIXLNBpWYBdbd6xN7CW/oTyEzjleVP4rOJ9iHSHOf73i80ZvXeJCY1NpqqCShLWt9mJpKFk+zJdPO0LSUHMmQNgGcKRYkSycO6ExZ11E1esJjK2ObTGlTciBTmM9vWxfIcFWizVUyN5IgnspJGaCMKgOmNMbmfAP9v2b/IsiR8m2K3l72OqcVUNm8AhAgNZQ98qblNk8TgtvDygY65eCfclkkg/Fzfn2zsXjiC3k3JeslWPQvnstzLVmafRDH7TAZBRkFgetv05I0HYqmD85hRlfNtrTvUBcZopOneIEzYlWnj9UeJaVLDYfR/7tT0v1VwHJhRxWT9rzH8U0S3kk62F7212xdH1kJphTycPPYSafFwztaDBWkF6AWh7zKw8= tonyg@zip