Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lost subject attributes #92

Closed
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ all: build

deps:
go get -u github.com/golang/dep/...
dep ensure -v
dep ensure -update -v

.pre:
mkdir -p build

build: build-scepclient build-scepserver
build: build-scepserver build-scepclient

build-scepclient: .pre
cd cmd/scepclient && ./release.sh
Expand Down
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ Usage of ./cmd/scepserver/scepserver:
validity for new client certificates in days (default "365")
-csrverifierexec string
will be passed the CSRs for verification
-certsuccesserexec string
will be passed the certs on successful generation
-certfailerexec string
will be passed the certs on failed generation
-debug
enable debug logging
-depot string
Expand Down
7 changes: 7 additions & 0 deletions certfailer/certfailer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Package certfailer defines an interface for cert failure notifications.
package certfailer

// Verify the raw decrypted CSR.
type CertFailer interface {
Fail(transactionID string, data []byte, errmsg string) (bool, error)
}
94 changes: 94 additions & 0 deletions certfailer/executable/certfailer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// Package executablecsrverifier defines the ExecutableCSRVerifier csrverifier.CSRVerifier.
package executablecertfailer

import (
"bufio"
"errors"
"os"
"os/exec"

"github.com/go-kit/kit/log"
)

const (
userExecute os.FileMode = 1 << (6 - 3*iota)
groupExecute
otherExecute
)

// New creates a executablecertfailer.ExecutableCertFailer.
func New(path string, logger log.Logger) (*ExecutableCertFailer, error) {
fileInfo, err := os.Stat(path)
if err != nil {
return nil, err
}

fileMode := fileInfo.Mode()
if fileMode.IsDir() {
return nil, errors.New("Cert Failer executable is a directory")
}

filePerm := fileMode.Perm()
if filePerm&(userExecute|groupExecute|otherExecute) == 0 {
return nil, errors.New("Cert Failer executable is not executable")
}

return &ExecutableCertFailer{executable: path, logger: logger}, nil
}

// ExecutableCertFailer implements a certfailer.CertFailer.
// It executes a command, and passes it the raw decrypted CSR and an error message.
// The exit code is ignored.
type ExecutableCertFailer struct {
executable string
logger log.Logger
}

func (v *ExecutableCertFailer) Fail(transactionID string, data []byte, errmsg string) (bool, error) {
cmd := exec.Command(v.executable, errmsg)
cmd.Env = append(os.Environ(), "TRANSACTIONID="+transactionID)

stdin, err := cmd.StdinPipe()
if err != nil {
return false, err
}
go func() {
defer stdin.Close()
stdin.Write(data)
}()

stdout, err := cmd.StdoutPipe()
if err != nil {
return false, err
}
go func() {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
v.logger.Log("info", "failer stdout: "+scanner.Text())
}
}()

stderr, err := cmd.StderrPipe()
if err != nil {
return false, err
}
go func() {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
v.logger.Log("info", "failer stderr: "+scanner.Text())
}
}()

if err := cmd.Start(); err != nil {
v.logger.Log("err", err)
// mask the executable error
return false, nil
}

if err := cmd.Wait(); err != nil {
v.logger.Log("err", err)
// mask the executable error
return false, nil
}
return true, err
}
7 changes: 7 additions & 0 deletions certsuccesser/certsucesser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
// Package certsuccesser defines an interface for cert success notifications.
package certsuccesser

// Verify the raw decrypted CSR.
type CertSuccesser interface {
Success(transactionID string, data []byte, certFilename string) (bool, error)
}
95 changes: 95 additions & 0 deletions certsuccesser/executable/certsuccesser.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
// Package executablecsrverifier defines the ExecutableCSRVerifier csrverifier.CSRVerifier.
package executablecertsuccesser

import (
"bufio"
"errors"
"os"
"os/exec"

"github.com/go-kit/kit/log"
)

const (
userExecute os.FileMode = 1 << (6 - 3*iota)
groupExecute
otherExecute
)

// New creates a executablecertsuccesser.ExecutableCertSuccesser.
func New(path string, logger log.Logger) (*ExecutableCertSuccesser, error) {
fileInfo, err := os.Stat(path)
if err != nil {
return nil, err
}

fileMode := fileInfo.Mode()
if fileMode.IsDir() {
return nil, errors.New("Cert Successer executable is a directory")
}

filePerm := fileMode.Perm()
if filePerm&(userExecute|groupExecute|otherExecute) == 0 {
return nil, errors.New("Cert Successer executable is not executable")
}

return &ExecutableCertSuccesser{executable: path, logger: logger}, nil
}

// ExecutableCertSuccesser implements a certsuccesser.CertSuccesser.
// It executes a command, and passes it the raw decrypted CSR and cert.
// If the command exit code is 0, the cert can be returned to the client.
// In any other cases, the cert is failed and the client gets an error.
type ExecutableCertSuccesser struct {
executable string
logger log.Logger
}

func (v *ExecutableCertSuccesser) Success(transactionID string, data []byte, certFilename string) (bool, error) {
cmd := exec.Command(v.executable, certFilename)
cmd.Env = append(os.Environ(), "TRANSACTIONID="+transactionID)

stdin, err := cmd.StdinPipe()
if err != nil {
return false, err
}
go func() {
defer stdin.Close()
stdin.Write(data)
}()

stdout, err := cmd.StdoutPipe()
if err != nil {
return false, err
}
go func() {
scanner := bufio.NewScanner(stdout)
for scanner.Scan() {
v.logger.Log("info", "successer stdout: "+scanner.Text())
}
}()

stderr, err := cmd.StderrPipe()
if err != nil {
return false, err
}
go func() {
scanner := bufio.NewScanner(stderr)
for scanner.Scan() {
v.logger.Log("info", "successer stderr: "+scanner.Text())
}
}()

if err := cmd.Start(); err != nil {
v.logger.Log("err", err)
// mask the executable error
return false, nil
}

if err := cmd.Wait(); err != nil {
v.logger.Log("err", err)
// mask the executable error
return false, nil
}
return true, err
}
2 changes: 1 addition & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"

"github.com/micromdm/scep/server"
"github.com/syncsynchalt/scep/server"
)

// Client is a SCEP Client
Expand Down
2 changes: 1 addition & 1 deletion cmd/scepclient/csr.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
"io/ioutil"
"os"

"github.com/micromdm/scep/crypto/x509util"
"github.com/syncsynchalt/scep/crypto/x509util"
)

const (
Expand Down
4 changes: 3 additions & 1 deletion cmd/scepclient/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ echo "Building $NAME version $VERSION"
mkdir -p ${OUTPUT}

build() {
set -e
echo -n "=> $1-$2: "
GOOS=$1 GOARCH=$2 go build -o ${OUTPUT}/$NAME-$1-$2 -ldflags "-X main.version=$VERSION -X main.gitHash=`git rev-parse HEAD`" ./*.go
du -h ${OUTPUT}/${NAME}-$1-$2
set +e
}

build "darwin" "amd64"
build "linux" "amd64"
#build "darwin" "amd64"
4 changes: 2 additions & 2 deletions cmd/scepclient/scepclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import (
"github.com/fullsailor/pkcs7"
"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/micromdm/scep/client"
"github.com/micromdm/scep/scep"
"github.com/syncsynchalt/scep/client"
"github.com/syncsynchalt/scep/scep"
"github.com/pkg/errors"
)

Expand Down
4 changes: 3 additions & 1 deletion cmd/scepserver/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ echo "Building $NAME version $VERSION"
mkdir -p ${OUTPUT}

build() {
set -e
echo -n "=> $1-$2: "
GOOS=$1 GOARCH=$2 go build -o ${OUTPUT}/$NAME-$1-$2 -ldflags "-X main.version=$VERSION -X main.gitHash=`git rev-parse HEAD`" ./*.go
du -h ${OUTPUT}/${NAME}-$1-$2
set +e
}

build "darwin" "amd64"
build "linux" "amd64"
#build "darwin" "amd64"
42 changes: 34 additions & 8 deletions cmd/scepserver/scepserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,15 @@ import (

"github.com/go-kit/kit/log"
"github.com/go-kit/kit/log/level"
"github.com/micromdm/scep/csrverifier"
"github.com/micromdm/scep/csrverifier/executable"
"github.com/micromdm/scep/depot"
"github.com/micromdm/scep/depot/file"
"github.com/micromdm/scep/server"
"github.com/syncsynchalt/scep/certfailer"
"github.com/syncsynchalt/scep/certfailer/executable"
"github.com/syncsynchalt/scep/certsuccesser"
"github.com/syncsynchalt/scep/certsuccesser/executable"
"github.com/syncsynchalt/scep/csrverifier"
"github.com/syncsynchalt/scep/csrverifier/executable"
"github.com/syncsynchalt/scep/depot"
"github.com/syncsynchalt/scep/depot/file"
"github.com/syncsynchalt/scep/server"
)

// version info
Expand Down Expand Up @@ -57,6 +61,8 @@ func main() {
flClAllowRenewal = flag.String("allowrenew", envString("SCEP_CERT_RENEW", "14"), "do not allow renewal until n days before expiry, set to 0 to always allow")
flChallengePassword = flag.String("challenge", envString("SCEP_CHALLENGE_PASSWORD", ""), "enforce a challenge password")
flCSRVerifierExec = flag.String("csrverifierexec", envString("SCEP_CSR_VERIFIER_EXEC", ""), "will be passed the CSRs for verification")
flCertSuccesserExec = flag.String("certsuccesserexec", envString("SCEP_CERT_SUCCESSER_EXEC", ""), "will be passed the certs on successful generation")
flCertFailerExec = flag.String("certfailerexec", envString("SCEP_CERT_FAILER_EXEC", ""), "will be called for failure to generate cert")
flDebug = flag.Bool("debug", envBool("SCEP_LOG_DEBUG"), "enable debug logging")
flLogJSON = flag.Bool("log-json", envBool("SCEP_LOG_JSON"), "output JSON logs")
)
Expand Down Expand Up @@ -104,29 +110,49 @@ func main() {
}
allowRenewal, err := strconv.Atoi(*flClAllowRenewal)
if err != nil {
lginfo.Log("No valid number for allowed renewal time : ", err)
lginfo.Log("err", err, "msg", "No valid number for allowed renewal time")
os.Exit(1)
}
clientValidity, err := strconv.Atoi(*flClDuration)
if err != nil {
lginfo.Log("No valid number for client cert validity : ", err)
lginfo.Log("err", err, "msg", "No valid number for client cert validity")
os.Exit(1)
}
var csrVerifier csrverifier.CSRVerifier
if *flCSRVerifierExec > "" {
executableCSRVerifier, err := executablecsrverifier.New(*flCSRVerifierExec, lginfo)
if err != nil {
lginfo.Log("Could not instantiate CSR verifier : ", err)
lginfo.Log("err", err, "msg", "Could not instantiate CSR verifier")
os.Exit(1)
}
csrVerifier = executableCSRVerifier
}
var certSuccesser certsuccesser.CertSuccesser
if *flCertSuccesserExec > "" {
executableCertSuccesser, err := executablecertsuccesser.New(*flCertSuccesserExec, lginfo)
if err != nil {
lginfo.Log("err", err, "msg", "Could not instantiate cert successer")
os.Exit(1)
}
certSuccesser = executableCertSuccesser
}
var certFailer certfailer.CertFailer
if *flCertFailerExec > "" {
executableCertFailer, err := executablecertfailer.New(*flCertFailerExec, lginfo)
if err != nil {
lginfo.Log("err", err, "msg", "Could not instantiate cert failer")
os.Exit(1)
}
certFailer = executableCertFailer
}

var svc scepserver.Service // scep service
{
svcOptions := []scepserver.ServiceOption{
scepserver.ChallengePassword(*flChallengePassword),
scepserver.WithCSRVerifier(csrVerifier),
scepserver.WithCertSuccesser(certSuccesser),
scepserver.WithCertFailer(certFailer),
scepserver.CAKeyPassword([]byte(*flCAPass)),
scepserver.ClientValidity(clientValidity),
scepserver.AllowRenewal(allowRenewal),
Expand Down
2 changes: 1 addition & 1 deletion csrverifier/csrverifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ package csrverifier

// Verify the raw decrypted CSR.
type CSRVerifier interface {
Verify(data []byte) (bool, error)
Verify(transactionID string, data []byte) (bool, error)
}
Loading