Skip to content

Commit

Permalink
Add -key-encipherment-selector and use CA certs for verification
Browse files Browse the repository at this point in the history
When a SCEP server returns multiple certificates, it is possible
that not all certificates can or should be used for encryption.
There already was a `KeyEnciphermentsSelector`, but that wasn't
readily usable with the provided SCEP client. A new flag was added
to enable this selector: `-key-encipherment-selector`. It will
filter out certificates that aren't marked as being usable for
key or data encryption.

When verifying the `PKIMessage` from the CA only the `Recipients`
in the outgoing message were being looked through when selecting
a certificate to verify the signature. This commit changes that
by including all certificates returned by the CA when the client
performs the `GetCACerts` operation.
  • Loading branch information
hslatman committed May 18, 2023
1 parent 699e8df commit 37da03c
Showing 1 changed file with 44 additions and 31 deletions.
75 changes: 44 additions & 31 deletions cmd/scepclient/scepclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,23 +115,23 @@ func run(cfg runCfg) error {
if err != nil {
return err
}
var certs []*x509.Certificate
var caCerts []*x509.Certificate
{
if certNum > 1 {
certs, err = scep.CACerts(resp)
caCerts, err = scep.CACerts(resp)
if err != nil {
return err
}
} else {
certs, err = x509.ParseCertificates(resp)
caCerts, err = x509.ParseCertificates(resp)
if err != nil {
return err
}
}
}

if cfg.debug {
logCerts(level.Debug(logger), certs)
logCerts(level.Debug(logger), caCerts)
}

var signerCert *x509.Certificate
Expand All @@ -155,7 +155,7 @@ func run(cfg runCfg) error {

tmpl := &scep.PKIMessage{
MessageType: msgType,
Recipients: certs,
Recipients: caCerts,
SignerKey: key,
SignerCert: signerCert,
}
Expand All @@ -182,7 +182,7 @@ func run(cfg runCfg) error {
return errors.Wrapf(err, "PKIOperation for %s", msgType)
}

respMsg, err = scep.ParsePKIMessage(respBytes, scep.WithLogger(logger), scep.WithCACerts(msg.Recipients))
respMsg, err = scep.ParsePKIMessage(respBytes, scep.WithLogger(logger), scep.WithCACerts(caCerts))
if err != nil {
return errors.Wrapf(err, "parsing pkiMessage response %s", msgType)
}
Expand Down Expand Up @@ -253,7 +253,36 @@ func validateFingerprint(fingerprint string) (hash []byte, err error) {
return
}

func validateFlags(keyPath, serverURL string) error {
var (
flVersion = flag.Bool("version", false, "prints version information")
flServerURL = flag.String("server-url", "", "SCEP server url")
flChallengePassword = flag.String("challenge", "", "enforce a challenge password")
flPKeyPath = flag.String("private-key", "", "private key path, if there is no key, scepclient will create one")
flCertPath = flag.String("certificate", "", "certificate path, if there is no key, scepclient will create one")
flKeySize = flag.Int("keySize", 2048, "rsa key size")
flOrg = flag.String("organization", "scep-client", "organization for cert")
flCName = flag.String("cn", "scepclient", "common name for certificate")
flOU = flag.String("ou", "MDM", "organizational unit for certificate")
flLoc = flag.String("locality", "", "locality for certificate")
flProvince = flag.String("province", "", "province for certificate")
flCountry = flag.String("country", "US", "country code in certificate")
flCACertMessage = flag.String("cacert-message", "", "message sent with GetCACert operation")
flDNSName = flag.String("dnsname", "", "DNS name to be included in the certificate (SAN)")

// in case of multiple certificate authorities, we need to figure out who the recipient of the encrypted
// data is.
flCAFingerprint = flag.String("ca-fingerprint", "", "SHA-256 digest of CA certificate for NDES server. Note: Changed from MD5.")
flKeyEnciphermentSelector = flag.Bool("key-encipherment-selector", false, "Filter CA certificates by key encipherment usage")

flDebugLogging = flag.Bool("debug", false, "enable debug logging")
flLogJSON = flag.Bool("log-json", false, "use JSON for log output")
)

func validateFlags() error {
keyPath := *flPKeyPath
serverURL := *flServerURL
caFingerprint := *flCAFingerprint
useKeyEnciphermentSelector := *flKeyEnciphermentSelector
if keyPath == "" {
return errors.New("must specify private key path")
}
Expand All @@ -264,33 +293,14 @@ func validateFlags(keyPath, serverURL string) error {
if err != nil {
return fmt.Errorf("invalid server-url flag parameter %s", err)
}
if caFingerprint != "" && useKeyEnciphermentSelector {
return errors.New("ca-fingerprint and key-encipherment-selector can't be used at the same time")
}
return nil
}

func main() {
var (
flVersion = flag.Bool("version", false, "prints version information")
flServerURL = flag.String("server-url", "", "SCEP server url")
flChallengePassword = flag.String("challenge", "", "enforce a challenge password")
flPKeyPath = flag.String("private-key", "", "private key path, if there is no key, scepclient will create one")
flCertPath = flag.String("certificate", "", "certificate path, if there is no key, scepclient will create one")
flKeySize = flag.Int("keySize", 2048, "rsa key size")
flOrg = flag.String("organization", "scep-client", "organization for cert")
flCName = flag.String("cn", "scepclient", "common name for certificate")
flOU = flag.String("ou", "MDM", "organizational unit for certificate")
flLoc = flag.String("locality", "", "locality for certificate")
flProvince = flag.String("province", "", "province for certificate")
flCountry = flag.String("country", "US", "country code in certificate")
flCACertMessage = flag.String("cacert-message", "", "message sent with GetCACert operation")
flDNSName = flag.String("dnsname", "", "DNS name to be included in the certificate (SAN)")

// in case of multiple certificate authorities, we need to figure out who the recipient of the encrypted
// data is.
flCAFingerprint = flag.String("ca-fingerprint", "", "SHA-256 digest of CA certificate for NDES server. Note: Changed from MD5.")

flDebugLogging = flag.Bool("debug", false, "enable debug logging")
flLogJSON = flag.Bool("log-json", false, "use JSON for log output")
)

flag.Parse()

// print version information
Expand All @@ -299,7 +309,7 @@ func main() {
os.Exit(0)
}

if err := validateFlags(*flPKeyPath, *flServerURL); err != nil {
if err := validateFlags(); err != nil {
fmt.Println(err)
os.Exit(1)
}
Expand All @@ -313,6 +323,9 @@ func main() {
}
caCertsSelector = scep.FingerprintCertsSelector(fingerprintHashType, hash)
}
if *flKeyEnciphermentSelector {
caCertsSelector = scep.EnciphermentCertsSelector()
}

dir := filepath.Dir(*flPKeyPath)
csrPath := dir + "/csr.pem"
Expand Down

0 comments on commit 37da03c

Please sign in to comment.