Browse Source

refactor: improve api semantics and configurability

Mustafa Arici 8 years ago
parent
commit
87c8f6faa1
7 changed files with 93 additions and 68 deletions
  1. 1 1
      cmd/ovpmd/main.go
  2. 3 2
      const.go
  3. 6 3
      db.go
  4. 9 0
      pki/const.go
  5. 59 59
      pki/pki.go
  6. 6 2
      user.go
  7. 9 1
      vpn.go

+ 1 - 1
cmd/ovpmd/main.go

@@ -42,7 +42,7 @@ func main() {
 		if c.GlobalBool("verbose") {
 			logrus.SetLevel(logrus.DebugLevel)
 		}
-		ovpm.SetupDB()
+		ovpm.SetupDB("sqlite3", "")
 		return nil
 	}
 	app.After = func(c *cli.Context) error {

+ 3 - 2
const.go

@@ -6,8 +6,9 @@ const (
 
 	// DefaultVPNPort is the default OpenVPN port to listen.
 	DefaultVPNPort = "1197"
-	etcBasePath    = "/etc/ovpm/"
-	varBasePath    = "/var/db/ovpm/"
+
+	etcBasePath = "/etc/ovpm/"
+	varBasePath = "/var/db/ovpm/"
 
 	_DefaultConfigPath   = etcBasePath + "ovpm.ini"
 	_DefaultDBPath       = varBasePath + "db.sqlite3"

+ 6 - 3
db.go

@@ -13,11 +13,14 @@ var db *gorm.DB
 // SetupDB prepares database for use.
 //
 // It should be run at the start of the program.
-func SetupDB() {
+func SetupDB(dialect string, args ...interface{}) {
+	if len(args) > 0 && args[0] == "" {
+		args[0] = _DefaultDBPath
+	}
 	var err error
-	db, err = gorm.Open("sqlite3", _DefaultDBPath)
+	db, err = gorm.Open(dialect, args...)
 	if err != nil {
-		logrus.Fatalf("couldn't open sqlite database %s: %v", _DefaultDBPath, err)
+		logrus.Fatalf("couldn't open sqlite database %v: %v", args, err)
 	}
 
 	db.AutoMigrate(&DBUser{})

+ 9 - 0
pki/const.go

@@ -0,0 +1,9 @@
+package pki
+
+// PEM encoding types
+const (
+	PEMCertificateBlockType   string = "CERTIFICATE"
+	PEMRSAPrivateKeyBlockType        = "RSA PRIVATE KEY"
+	PEMx509CRLBlockType              = "X509 CRL"
+	PEMCSRBlockType                  = "CERTIFICATE REQUEST"
+)

+ 59 - 59
pki/pki.go

@@ -70,7 +70,7 @@ func NewCA() (*CA, error) {
 	}
 
 	csr := pem.EncodeToMemory(&pem.Block{
-		Type: "CERTIFICATE REQUEST", Bytes: csrCertificate,
+		Type: PEMCSRBlockType, Bytes: csrCertificate,
 	})
 
 	// Serial number
@@ -100,10 +100,10 @@ func NewCA() (*CA, error) {
 
 	var request bytes.Buffer
 	var privateKey bytes.Buffer
-	if err := pem.Encode(&request, &pem.Block{Type: "CERTIFICATE", Bytes: certificate}); err != nil {
+	if err := pem.Encode(&request, &pem.Block{Type: PEMCertificateBlockType, Bytes: certificate}); err != nil {
 		return nil, err
 	}
-	if err := pem.Encode(&privateKey, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil {
+	if err := pem.Encode(&privateKey, &pem.Block{Type: PEMRSAPrivateKeyBlockType, Bytes: x509.MarshalPKCS1PrivateKey(key)}); err != nil {
 		return nil, err
 	}
 
@@ -117,64 +117,18 @@ func NewCA() (*CA, error) {
 
 }
 
-// NewServerCertHolder generates a x509 certificate and a key-pair for the server.
+// NewServerCertHolder generates a RSA key-pair and a x509 certificate signed by the CA for the server.
 func NewServerCertHolder(ca *CA) (*CertHolder, error) {
-	return newCert("localhost", ca, true)
+	return newCert(ca, true, "localhost")
 }
 
-// NewClientCertHolder generates a x509 certificate and a key-pair for the client.
-func NewClientCertHolder(username string, ca *CA) (*CertHolder, error) {
-	return newCert(username, ca, false)
+// NewClientCertHolder generates a RSA key-pair and a x509 certificate signed by the CA for the client.
+func NewClientCertHolder(ca *CA, username string) (*CertHolder, error) {
+	return newCert(ca, false, username)
 }
 
-// NewCRL takes in a list of certificate serial numbers to-be-revoked and a CA then makes a PEM encoded CRL and returns it as a string.
-func NewCRL(serials []*big.Int, ca *CA) (string, error) {
-	caCrt, err := ReadCertFromPEM(ca.Cert)
-	if err != nil {
-		return "", err
-	}
-
-	block, _ := pem.Decode([]byte(ca.Key))
-	if block == nil {
-		return "", fmt.Errorf("failed to parse ca private key")
-	}
-
-	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
-	if err != nil {
-		return "", fmt.Errorf("failed to parse ca private key: %s", err)
-	}
-	var revokedCertList []pkix.RevokedCertificate
-	for _, serial := range serials {
-		revokedCert := pkix.RevokedCertificate{
-			SerialNumber:   serial,
-			RevocationTime: time.Now().UTC(),
-		}
-		revokedCertList = append(revokedCertList, revokedCert)
-	}
-	crl, err := caCrt.CreateCRL(rand.Reader, priv, revokedCertList, time.Now().UTC(), time.Now().Add(365*24*60*time.Minute).UTC())
-	if err != nil {
-		return "", err
-	}
-
-	crlPem := pem.EncodeToMemory(&pem.Block{
-		Type:  "X509 CRL",
-		Bytes: crl,
-	})
-
-	return string(crlPem[:]), nil
-
-}
-
-// ReadCertFromPEM decodes a PEM encoded string into a x509.Certificate.
-func ReadCertFromPEM(s string) (*x509.Certificate, error) {
-	block, _ := pem.Decode([]byte(s))
-	var cert *x509.Certificate
-	cert, _ = x509.ParseCertificate(block.Bytes)
-	return cert, nil
-}
-
-// newCert generates a private key and a certificate, that is signed by the given CA.
-func newCert(cn string, ca *CA, server bool) (*CertHolder, error) {
+// newCert generates a RSA key-pair and a x509 certificate signed by the CA.
+func newCert(ca *CA, server bool, cn string) (*CertHolder, error) {
 	// Get CA private key
 	block, _ := pem.Decode([]byte(ca.Key))
 	if block == nil {
@@ -208,7 +162,7 @@ func newCert(cn string, ca *CA, server bool) (*CertHolder, error) {
 		SerialNumber: serial,
 		Subject: pkix.Name{
 			CommonName:   cn,
-			Organization: []string{"Innovation"},
+			Organization: []string{"OVPM"},
 		},
 		ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
 		BasicConstraintsValid: true,
@@ -225,12 +179,12 @@ func newCert(cn string, ca *CA, server bool) (*CertHolder, error) {
 	}
 
 	priKeyPem := pem.EncodeToMemory(&pem.Block{
-		Type:  "RSA PRIVATE KEY",
+		Type:  PEMRSAPrivateKeyBlockType,
 		Bytes: x509.MarshalPKCS1PrivateKey(key),
 	})
 
 	certPem := pem.EncodeToMemory(&pem.Block{
-		Type:  "CERTIFICATE",
+		Type:  PEMCertificateBlockType,
 		Bytes: cert,
 	})
 
@@ -239,3 +193,49 @@ func newCert(cn string, ca *CA, server bool) (*CertHolder, error) {
 		Cert: string(certPem[:]),
 	}, nil
 }
+
+// NewCRL takes in a list of certificate serial numbers to-be-revoked and a CA then makes a PEM encoded CRL and returns it as a string.
+func NewCRL(ca *CA, serials ...*big.Int) (string, error) {
+	caCrt, err := ReadCertFromPEM(ca.Cert)
+	if err != nil {
+		return "", err
+	}
+
+	block, _ := pem.Decode([]byte(ca.Key))
+	if block == nil {
+		return "", fmt.Errorf("failed to parse ca private key")
+	}
+
+	priv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+	if err != nil {
+		return "", fmt.Errorf("failed to parse ca private key: %s", err)
+	}
+	var revokedCertList []pkix.RevokedCertificate
+	for _, serial := range serials {
+		revokedCert := pkix.RevokedCertificate{
+			SerialNumber:   serial,
+			RevocationTime: time.Now().UTC(),
+		}
+		revokedCertList = append(revokedCertList, revokedCert)
+	}
+	crl, err := caCrt.CreateCRL(rand.Reader, priv, revokedCertList, time.Now().UTC(), time.Now().Add(365*24*60*time.Minute).UTC())
+	if err != nil {
+		return "", err
+	}
+
+	crlPem := pem.EncodeToMemory(&pem.Block{
+		Type:  PEMx509CRLBlockType,
+		Bytes: crl,
+	})
+
+	return string(crlPem[:]), nil
+
+}
+
+// ReadCertFromPEM decodes a PEM encoded string into a x509.Certificate.
+func ReadCertFromPEM(s string) (*x509.Certificate, error) {
+	block, _ := pem.Decode([]byte(s))
+	var cert *x509.Certificate
+	cert, _ = x509.ParseCertificate(block.Bytes)
+	return cert, nil
+}

+ 6 - 2
user.go

@@ -42,6 +42,10 @@ func (u *DBUser) setPassword(password string) error {
 	return nil
 }
 
+func (u *DBUser) checkPassword(password string) bool {
+	return u.Password == password
+}
+
 // GetUser finds and returns the user with the given username from database.
 func GetUser(username string) (*DBUser, error) {
 	user := DBUser{}
@@ -81,7 +85,7 @@ func CreateNewUser(username, password string) (*DBUser, error) {
 		return nil, err
 	}
 
-	clientCert, err := pki.NewClientCertHolder(username, ca)
+	clientCert, err := pki.NewClientCertHolder(ca, username)
 	if err != nil {
 		return nil, fmt.Errorf("can not create client cert %s: %v", username, err)
 	}
@@ -161,7 +165,7 @@ func (u *DBUser) Sign() error {
 		return err
 	}
 
-	clientCert, err := pki.NewClientCertHolder(u.Username, ca)
+	clientCert, err := pki.NewClientCertHolder(ca, u.Username)
 	if err != nil {
 		return fmt.Errorf("can not create client cert %s: %v", u.Username, err)
 	}

+ 9 - 1
vpn.go

@@ -68,6 +68,14 @@ type _VPNServerConfig struct {
 
 // Init regenerates keys and certs for a Root CA, and saves them in the database.
 func Init(hostname string, port string) error {
+	if port == "" {
+		port = DefaultVPNPort
+	}
+
+	if !govalidator.IsNumeric(port) {
+		return fmt.Errorf("validation error: port:`%s` should be numeric", hostname)
+	}
+
 	serverName := "default"
 	if IsInitialized() {
 		if err := Deinit(); err != nil {
@@ -410,7 +418,7 @@ func emitCRL() error {
 	if err != nil {
 		return fmt.Errorf("can not emit CRL: %v", err)
 	}
-	crl, err := pki.NewCRL(revokedCertSerials, systemCA)
+	crl, err := pki.NewCRL(systemCA, revokedCertSerials...)
 	if err != nil {
 		return fmt.Errorf("can not emit crl: %v", err)
 	}