| 95 | var keyGenMu sync.Mutex |
| 96 | |
| 97 | func hostKeyFileOrCreate(keyDir, typ string) ([]byte, error) { |
| 98 | keyGenMu.Lock() |
| 99 | defer keyGenMu.Unlock() |
| 100 | |
| 101 | path := filepath.Join(keyDir, "ssh_host_"+typ+"_key") |
| 102 | v, err := os.ReadFile(path) |
| 103 | if err == nil { |
| 104 | return v, nil |
| 105 | } |
| 106 | if !os.IsNotExist(err) { |
| 107 | return nil, err |
| 108 | } |
| 109 | var priv any |
| 110 | switch typ { |
| 111 | default: |
| 112 | return nil, fmt.Errorf("unsupported key type %q", typ) |
| 113 | case "ed25519": |
| 114 | _, priv, err = ed25519.GenerateKey(rand.Reader) |
| 115 | case "ecdsa": |
| 116 | // curve is arbitrary. We pick whatever will at |
| 117 | // least pacify clients as the actual encryption |
| 118 | // doesn't matter: it's all over WireGuard anyway. |
| 119 | curve := elliptic.P256() |
| 120 | priv, err = ecdsa.GenerateKey(curve, rand.Reader) |
| 121 | case "rsa": |
| 122 | // keySize is arbitrary. We pick whatever will at |
| 123 | // least pacify clients as the actual encryption |
| 124 | // doesn't matter: it's all over WireGuard anyway. |
| 125 | const keySize = 2048 |
| 126 | priv, err = rsa.GenerateKey(rand.Reader, keySize) |
| 127 | } |
| 128 | if err != nil { |
| 129 | return nil, err |
| 130 | } |
| 131 | mk, err := x509.MarshalPKCS8PrivateKey(priv) |
| 132 | if err != nil { |
| 133 | return nil, err |
| 134 | } |
| 135 | pemGen := pem.EncodeToMemory(&pem.Block{Type: "PRIVATE KEY", Bytes: mk}) |
| 136 | err = os.WriteFile(path, pemGen, 0700) |
| 137 | return pemGen, err |
| 138 | } |
| 139 | |
| 140 | func getSystemHostKeys(logf logger.Logf) (ret map[string]ssh.Signer) { |
| 141 | for _, typ := range keyTypes { |