|
@@ -1,9 +1,19 @@
|
1
|
1
|
package main
|
2
|
2
|
|
3
|
3
|
import (
|
|
4
|
+ "crypto/ecdsa"
|
|
5
|
+ "crypto/elliptic"
|
|
6
|
+ "crypto/rand"
|
|
7
|
+ "crypto/x509"
|
|
8
|
+ "crypto/x509/pkix"
|
|
9
|
+ "encoding/pem"
|
4
|
10
|
"fmt"
|
5
|
11
|
"log"
|
|
12
|
+ "math/big"
|
|
13
|
+ "net"
|
|
14
|
+ "os"
|
6
|
15
|
"syscall"
|
|
16
|
+ "time"
|
7
|
17
|
|
8
|
18
|
"github.com/DanielOaks/oragono/irc"
|
9
|
19
|
"github.com/docopt/docopt-go"
|
|
@@ -17,6 +27,7 @@ Usage:
|
17
|
27
|
oragono initdb [--conf <filename>]
|
18
|
28
|
oragono upgradedb [--conf <filename>]
|
19
|
29
|
oragono genpasswd [--conf <filename>]
|
|
30
|
+ oragono createcerts [--conf <filename>]
|
20
|
31
|
oragono run [--conf <filename>]
|
21
|
32
|
oragono -h | --help
|
22
|
33
|
oragono --version
|
|
@@ -52,6 +63,71 @@ Options:
|
52
|
63
|
} else if arguments["upgradedb"].(bool) {
|
53
|
64
|
irc.UpgradeDB(config.Server.Database)
|
54
|
65
|
log.Println("database upgraded: ", config.Server.Database)
|
|
66
|
+ } else if arguments["createcerts"].(bool) {
|
|
67
|
+ log.Println("creating self-signed certificates")
|
|
68
|
+
|
|
69
|
+ for name, conf := range config.Server.TLSListeners {
|
|
70
|
+ log.Printf(" creating cert for %s listener\n", name)
|
|
71
|
+ host := config.Server.Name
|
|
72
|
+ validFrom := time.Now()
|
|
73
|
+ validFor := 365 * 24 * time.Hour
|
|
74
|
+ notAfter := validFrom.Add(validFor)
|
|
75
|
+
|
|
76
|
+ priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
|
|
77
|
+
|
|
78
|
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
|
|
79
|
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
|
|
80
|
+ if err != nil {
|
|
81
|
+ log.Fatalf("failed to generate serial number: %s", err)
|
|
82
|
+ }
|
|
83
|
+
|
|
84
|
+ template := x509.Certificate{
|
|
85
|
+ SerialNumber: serialNumber,
|
|
86
|
+ Subject: pkix.Name{
|
|
87
|
+ Organization: []string{"Oragono"},
|
|
88
|
+ },
|
|
89
|
+ NotBefore: validFrom,
|
|
90
|
+ NotAfter: notAfter,
|
|
91
|
+
|
|
92
|
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
|
|
93
|
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
|
|
94
|
+ BasicConstraintsValid: true,
|
|
95
|
+ }
|
|
96
|
+
|
|
97
|
+ // TODO: allow explicitly listing allowed addresses/names
|
|
98
|
+ template.IPAddresses = append(template.IPAddresses, net.ParseIP("127.0.0.1"))
|
|
99
|
+ template.IPAddresses = append(template.IPAddresses, net.ParseIP("::1"))
|
|
100
|
+ template.DNSNames = append(template.DNSNames, host)
|
|
101
|
+ template.DNSNames = append(template.DNSNames, "localhost")
|
|
102
|
+
|
|
103
|
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, &priv.PublicKey, priv)
|
|
104
|
+ if err != nil {
|
|
105
|
+ log.Fatalf("Failed to create certificate: %s", err)
|
|
106
|
+ }
|
|
107
|
+
|
|
108
|
+ certOut, err := os.Create(conf.Cert)
|
|
109
|
+ if err != nil {
|
|
110
|
+ log.Fatalf("failed to open %s for writing: %s", conf.Cert, err)
|
|
111
|
+ }
|
|
112
|
+ pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes})
|
|
113
|
+ certOut.Close()
|
|
114
|
+ log.Printf(" wrote %s\n", conf.Cert)
|
|
115
|
+
|
|
116
|
+ keyOut, err := os.OpenFile(conf.Key, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
|
|
117
|
+ if err != nil {
|
|
118
|
+ log.Print("failed to open %s for writing:", conf.Key, err)
|
|
119
|
+ return
|
|
120
|
+ }
|
|
121
|
+ b, err := x509.MarshalECPrivateKey(priv)
|
|
122
|
+ if err != nil {
|
|
123
|
+ fmt.Fprintf(os.Stderr, "Unable to marshal ECDSA private key: %v", err)
|
|
124
|
+ os.Exit(2)
|
|
125
|
+ }
|
|
126
|
+ pemBlock := pem.Block{Type: "EC PRIVATE KEY", Bytes: b}
|
|
127
|
+ pem.Encode(keyOut, &pemBlock)
|
|
128
|
+ keyOut.Close()
|
|
129
|
+ log.Printf(" wrote %s\n", conf.Key)
|
|
130
|
+ }
|
55
|
131
|
} else if arguments["run"].(bool) {
|
56
|
132
|
irc.Log.SetLevel(config.Server.Log)
|
57
|
133
|
server := irc.NewServer(config)
|