Changeset 307 in code for trunk/service.go
- Timestamp:
- Jun 2, 2020, 9:24:22 AM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/service.go
r279 r307 2 2 3 3 import ( 4 "crypto" 5 "crypto/ecdsa" 6 "crypto/ed25519" 7 "crypto/elliptic" 8 "crypto/rand" 9 "crypto/rsa" 10 "crypto/sha1" 11 "crypto/sha256" 12 "crypto/x509" 13 "crypto/x509/pkix" 14 "encoding/hex" 15 "errors" 4 16 "flag" 5 17 "fmt" 6 18 "io/ioutil" 19 "math/big" 7 20 "strings" 21 "time" 8 22 9 23 "github.com/google/shlex" … … 120 134 }, 121 135 }, 136 "certfp": { 137 children: serviceCommandSet{ 138 "generate": { 139 usage: "[-key-type rsa|ecdsa|ed25519] [-bits N] <network name>", 140 desc: "generate a new self-signed certificate, defaults to using RSA-3072 key", 141 handle: handleServiceCertfpGenerate, 142 }, 143 "fingerprint": { 144 usage: "<network name>", 145 desc: "show fingerprints of certificate associated with the network", 146 handle: handleServiceCertfpFingerprints, 147 }, 148 "reset": { 149 usage: "<network name>", 150 desc: "disable SASL EXTERNAL authentication and remove stored certificate", 151 handle: handleServiceCertfpReset, 152 }, 153 }, 154 }, 122 155 "change-password": { 123 156 usage: "<new password>", … … 126 159 }, 127 160 } 161 } 162 163 func handleServiceCertfpGenerate(dc *downstreamConn, params []string) error { 164 fs := newFlagSet() 165 keyType := fs.String("key-type", "rsa", "key type to generate (rsa, ecdsa, ed25519)") 166 bits := fs.Int("bits", 3072, "size of key to generate, meaningful only for RSA") 167 168 if err := fs.Parse(params); err != nil { 169 return err 170 } 171 172 if len(fs.Args()) != 1 { 173 return errors.New("exactly one argument is required") 174 } 175 176 net := dc.user.getNetwork(fs.Arg(0)) 177 if net == nil { 178 return fmt.Errorf("unknown network %q", fs.Arg(0)) 179 } 180 181 var ( 182 privKey crypto.PrivateKey 183 pubKey crypto.PublicKey 184 ) 185 switch *keyType { 186 case "rsa": 187 key, err := rsa.GenerateKey(rand.Reader, *bits) 188 if err != nil { 189 return err 190 } 191 privKey = key 192 pubKey = key.Public() 193 case "ecdsa": 194 key, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader) 195 if err != nil { 196 return err 197 } 198 privKey = key 199 pubKey = key.Public() 200 case "ed25519": 201 var err error 202 pubKey, privKey, err = ed25519.GenerateKey(rand.Reader) 203 if err != nil { 204 return err 205 } 206 } 207 208 // Using PKCS#8 allows easier extension for new key types. 209 privKeyBytes, err := x509.MarshalPKCS8PrivateKey(privKey) 210 if err != nil { 211 return err 212 } 213 214 notBefore := time.Now() 215 // Lets make a fair assumption nobody will use the same cert for more than 20 years... 216 notAfter := notBefore.Add(24 * time.Hour * 365 * 20) 217 serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) 218 serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) 219 if err != nil { 220 return err 221 } 222 cert := &x509.Certificate{ 223 SerialNumber: serialNumber, 224 Subject: pkix.Name{CommonName: "soju auto-generated certificate"}, 225 NotBefore: notBefore, 226 NotAfter: notAfter, 227 KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, 228 ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, 229 } 230 derBytes, err := x509.CreateCertificate(rand.Reader, cert, cert, pubKey, privKey) 231 if err != nil { 232 return err 233 } 234 235 net.SASL.External.CertBlob = derBytes 236 net.SASL.External.PrivKeyBlob = privKeyBytes 237 net.SASL.Mechanism = "EXTERNAL" 238 239 if err := dc.srv.db.StoreNetwork(net.Username, &net.Network); err != nil { 240 return err 241 } 242 243 sendServicePRIVMSG(dc, "certificate generated") 244 245 sha1Sum := sha1.Sum(derBytes) 246 sendServicePRIVMSG(dc, "SHA-1 fingerprint: "+hex.EncodeToString(sha1Sum[:])) 247 sha256Sum := sha256.Sum256(derBytes) 248 sendServicePRIVMSG(dc, "SHA-256 fingerprint: "+hex.EncodeToString(sha256Sum[:])) 249 250 return nil 251 } 252 253 func handleServiceCertfpFingerprints(dc *downstreamConn, params []string) error { 254 if len(params) != 1 { 255 return fmt.Errorf("expected exactly one argument") 256 } 257 258 net := dc.user.getNetwork(params[0]) 259 if net == nil { 260 return fmt.Errorf("unknown network %q", params[0]) 261 } 262 263 sha1Sum := sha1.Sum(net.SASL.External.CertBlob) 264 sendServicePRIVMSG(dc, "SHA-1 fingerprint: "+hex.EncodeToString(sha1Sum[:])) 265 sha256Sum := sha256.Sum256(net.SASL.External.CertBlob) 266 sendServicePRIVMSG(dc, "SHA-256 fingerprint: "+hex.EncodeToString(sha256Sum[:])) 267 return nil 268 } 269 270 func handleServiceCertfpReset(dc *downstreamConn, params []string) error { 271 if len(params) != 1 { 272 return fmt.Errorf("expected exactly one argument") 273 } 274 275 net := dc.user.getNetwork(params[0]) 276 if net == nil { 277 return fmt.Errorf("unknown network %q", params[0]) 278 } 279 280 net.SASL.External.CertBlob = nil 281 net.SASL.External.PrivKeyBlob = nil 282 283 if net.SASL.Mechanism == "EXTERNAL" { 284 net.SASL.Mechanism = "" 285 } 286 if err := dc.srv.db.StoreNetwork(dc.user.Username, &net.Network); err != nil { 287 return err 288 } 289 290 sendServicePRIVMSG(dc, "certificate reset") 291 return nil 128 292 } 129 293
Note:
See TracChangeset
for help on using the changeset viewer.