diff --git a/cmd/keygen.go b/cmd/keygen.go index 82e2e22..f9fbf14 100644 --- a/cmd/keygen.go +++ b/cmd/keygen.go @@ -4,28 +4,29 @@ import ( "crypto/rand" "crypto/rsa" "crypto/x509" - "crypto/x509/pkix" "encoding/pem" "fmt" + "io/ioutil" "log" - "math/big" - "os" - "time" + "strings" - "github.com/MDrollette/go-i2p/reseed" + "github.com/MDrollette/go-i2p/su3" "github.com/codegangsta/cli" ) func NewKeygenCommand() cli.Command { return cli.Command{ - Name: "keygen", - Usage: "Generate keys for reseed SU3 signing", - Description: "Generate keys for reseed SU3 signing", - Action: keygenAction, + Name: "keygen", + Usage: "Generate keys for reseed su3 signing and TLS serving.", + Action: keygenAction, Flags: []cli.Flag{ cli.StringFlag{ Name: "signer", - Usage: "Your SU3 signing ID (your email address)", + Usage: "Your su3 signing ID (ex. something@mail.i2p)", + }, + cli.StringFlag{ + Name: "host", + Usage: "Hostname to use for self-signed TLS certificate", }, }, } @@ -38,66 +39,26 @@ func keygenAction(c *cli.Context) { return } - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - log.Fatalf("failed to generate serial number: %s", err) - } - - template := &x509.Certificate{ - BasicConstraintsValid: true, - IsCA: true, - SubjectKeyId: []byte(signerId), - SerialNumber: serialNumber, - Subject: pkix.Name{ - Organization: []string{"I2P Anonymous Network"}, - OrganizationalUnit: []string{"I2P"}, - Locality: []string{"XX"}, - StreetAddress: []string{"XX"}, - Country: []string{"XX"}, - CommonName: signerId, - }, - NotBefore: time.Now(), - NotAfter: time.Now().AddDate(10, 0, 0), - ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, - KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, - } - // generate private key fmt.Println("Generating keys. This may take a moment...") - privatekey, err := rsa.GenerateKey(rand.Reader, 4096) + signerKey, err := rsa.GenerateKey(rand.Reader, 4096) if err != nil { log.Fatalln(err) } - publickey := &privatekey.PublicKey - - // create a self-signed certificate. template = parent - var parent = template - cert, err := x509.CreateCertificate(rand.Reader, template, parent, publickey, privatekey) - if err != nil { - log.Fatalln(err) - } + signerCert, err := su3.NewSigningCertificate(signerId, signerKey) // save private key - pemfile, err := os.Create("reseed_private.pem") - if err != nil { - log.Fatalf("failed to open reseed_cert.pem for writing: %s", err) + privFile := strings.Replace(signerId, "@", "_at_", 1) + ".pem" + if ioutil.WriteFile(privFile, pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(signerKey)}), 0600); err != nil { + log.Fatalln(err) } - var pemkey = &pem.Block{ - Type: "RSA PRIVATE KEY", - Bytes: x509.MarshalPKCS1PrivateKey(privatekey)} - pem.Encode(pemfile, pemkey) - pemfile.Close() - fmt.Println("private key saved to reseed_private.pem") + fmt.Println("private key saved to:", privFile) // save cert - filename := reseed.SignerFilename(signerId) - certOut, err := os.Create(filename) - if err != nil { - log.Fatalf("failed to open %s for writing: %s", filename, err) + certFile := strings.Replace(signerId, "@", "_at_", 1) + ".crt" + if ioutil.WriteFile(certFile, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: signerCert}), 0755); err != nil { + log.Fatalln(err) } - pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: cert}) - certOut.Close() - fmt.Println("certificate saved to", filename) + fmt.Println("certificate saved to", certFile) } diff --git a/cmd/reseeder.go b/cmd/reseeder.go index 3d43854..3b18546 100644 --- a/cmd/reseeder.go +++ b/cmd/reseeder.go @@ -13,14 +13,13 @@ import ( func NewReseedCommand() cli.Command { return cli.Command{ - Name: "reseed", - Usage: "Start a reseed server", - Description: "Start a reseed server", - Action: reseedAction, + Name: "reseed", + Usage: "Start a reseed server", + Action: reseedAction, Flags: []cli.Flag{ cli.StringFlag{ Name: "signer", - Usage: "Your SU3 signing ID (your email address)", + Usage: "Your su3 signing ID (ex. something@mail.i2p)", }, cli.StringFlag{ Name: "netdb", @@ -76,6 +75,7 @@ func NewReseedCommand() cli.Command { } func reseedAction(c *cli.Context) { + // validate flags netdbDir := c.String("netdb") if netdbDir == "" { fmt.Println("--netdb is required") @@ -93,13 +93,12 @@ func reseedAction(c *cli.Context) { log.Fatalf("'%s' is not a valid time interval.\n", reloadIntvl) } - // use at most half of the cores + // use all cores cpus := runtime.NumCPU() runtime.GOMAXPROCS(cpus) log.Printf("Using %d CPU cores.\n", cpus) // load our signing privKey - // @todo: generate a new signing key if one doesn't exist privKey, err := loadPrivateKey(c.String("keyfile")) if nil != err { log.Fatalln(err) diff --git a/main.go b/main.go index 9941e8b..3594cc2 100644 --- a/main.go +++ b/main.go @@ -9,7 +9,7 @@ import ( func main() { app := cli.NewApp() - app.Name = "i2p" + app.Name = "go-i2p" app.Version = "0.1.0" app.Usage = "I2P commands" app.Flags = []cli.Flag{} diff --git a/reseed/keystore.go b/reseed/keystore.go index aca63fb..13c1ad7 100644 --- a/reseed/keystore.go +++ b/reseed/keystore.go @@ -24,5 +24,5 @@ func (ks *KeyStore) ReseederCertificate(signer []byte) (*x509.Certificate, error } func SignerFilename(signer string) string { - return strings.Replace(signer, "@", "_at_", 2) + ".crt" + return strings.Replace(signer, "@", "_at_", 1) + ".crt" } diff --git a/reseed/utils.go b/reseed/zip.go similarity index 93% rename from reseed/utils.go rename to reseed/zip.go index 35e0d15..911a422 100644 --- a/reseed/utils.go +++ b/reseed/zip.go @@ -16,7 +16,7 @@ func zipSeeds(seeds Seeds) ([]byte, error) { // Add some files to the archive. for _, file := range seeds { - fileHeader := &zip.FileHeader{Name: file.Name} + fileHeader := &zip.FileHeader{Name: file.Name, Method: zip.Deflate} fileHeader.SetModTime(time.Now().UTC()) zipFile, err := zipWriter.CreateHeader(fileHeader) if err != nil { diff --git a/su3/crypto.go b/su3/crypto.go index 007e03c..d1443e6 100644 --- a/su3/crypto.go +++ b/su3/crypto.go @@ -4,11 +4,14 @@ import ( "crypto" "crypto/dsa" "crypto/ecdsa" + "crypto/rand" "crypto/rsa" "crypto/x509" + "crypto/x509/pkix" "encoding/asn1" "errors" "math/big" + "time" ) type dsaSignature struct { @@ -72,3 +75,41 @@ func checkSignature(c *x509.Certificate, algo x509.SignatureAlgorithm, signed, s } return x509.ErrUnsupportedAlgorithm } + +func NewSigningCertificate(signerId string, privateKey *rsa.PrivateKey) ([]byte, error) { + serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) + serialNumber, err := rand.Int(rand.Reader, serialNumberLimit) + if err != nil { + return nil, err + } + + template := &x509.Certificate{ + BasicConstraintsValid: true, + IsCA: true, + SubjectKeyId: []byte(signerId), + SerialNumber: serialNumber, + Subject: pkix.Name{ + Organization: []string{"I2P Anonymous Network"}, + OrganizationalUnit: []string{"I2P"}, + Locality: []string{"XX"}, + StreetAddress: []string{"XX"}, + Country: []string{"XX"}, + CommonName: signerId, + }, + NotBefore: time.Now(), + NotAfter: time.Now().AddDate(10, 0, 0), + ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth, x509.ExtKeyUsageServerAuth}, + KeyUsage: x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign, + } + + publicKey := &privateKey.PublicKey + + // create a self-signed certificate. template = parent + var parent = template + cert, err := x509.CreateCertificate(rand.Reader, template, parent, publicKey, privateKey) + if err != nil { + return nil, err + } + + return cert, nil +}