11use core:: net:: { Ipv4Addr , SocketAddr } ;
2- use std:: sync:: Arc ;
2+ use std:: {
3+ fs:: { self , File } ,
4+ io:: { self , Write } ,
5+ sync:: Arc ,
6+ } ;
37
48use aws_lc_rs:: signature:: Ed25519KeyPair ;
59use clap:: Parser ;
@@ -16,6 +20,25 @@ async fn main() -> anyhow::Result<()> {
1620
1721 let args = Args :: parse ( ) ;
1822
23+ let host_key = Arc :: new ( if args. generate_host_key {
24+ match File :: create_new ( & args. host_key_file ) {
25+ Ok ( mut host_key_file) => {
26+ let Ok ( host_key) = Ed25519KeyPair :: generate ( ) else {
27+ anyhow:: bail!( "failed to generate host key" ) ;
28+ } ;
29+ // FIXME ensure the host key is only readable by the ssh server user
30+ host_key_file. write_all ( host_key. to_pkcs8v1 ( ) ?. as_ref ( ) ) ?;
31+ host_key
32+ }
33+ Err ( err) if err. kind ( ) == io:: ErrorKind :: AlreadyExists => {
34+ anyhow:: bail!( "host key file `{}` already exists" , & args. host_key_file) ;
35+ }
36+ Err ( err) => return Err ( err. into ( ) ) ,
37+ }
38+ } else {
39+ Ed25519KeyPair :: from_pkcs8 ( & fs:: read ( args. host_key_file ) ?) ?
40+ } ) ;
41+
1942 let listener = match ( ListenFd :: from_env ( ) . take_tcp_listener ( 0 ) ?, args. port ) {
2043 ( Some ( listener) , None ) => {
2144 listener. set_nonblocking ( true ) ?;
@@ -30,11 +53,6 @@ async fn main() -> anyhow::Result<()> {
3053 } ;
3154 info ! ( addr = %listener. local_addr( ) ?, "listening for connections" ) ;
3255
33- let Ok ( host_key) = Ed25519KeyPair :: generate ( ) else {
34- anyhow:: bail!( "failed to generate host key" ) ;
35- } ;
36- let host_key = Arc :: new ( host_key) ;
37-
3856 loop {
3957 match listener. accept ( ) . await {
4058 Ok ( ( stream, addr) ) => {
@@ -54,4 +72,8 @@ async fn main() -> anyhow::Result<()> {
5472struct Args {
5573 #[ clap( short, long) ]
5674 port : Option < u16 > ,
75+ #[ clap( long, default_value = "ssh_host_ed25519_key" ) ]
76+ host_key_file : String ,
77+ #[ clap( long) ]
78+ generate_host_key : bool ,
5779}
0 commit comments