Skip to content

Commit

Permalink
Add -key-encipherment-selector and use CA certs for verification (#217
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 authored Jul 15, 2024
1 parent c5e4c78 commit 781f804
Showing 1 changed file with 20 additions and 11 deletions.
31 changes: 20 additions & 11 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,7 @@ func validateFingerprint(fingerprint string) (hash []byte, err error) {
return
}

func validateFlags(keyPath, serverURL string) error {
func validateFlags(keyPath, serverURL, caFingerprint string, useKeyEnciphermentSelector bool) error {
if keyPath == "" {
return errors.New("must specify private key path")
}
Expand All @@ -264,6 +264,9 @@ 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
}

Expand All @@ -285,12 +288,15 @@ func main() {
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.")
// data is. This can be done using either the CA fingerprint, or based on the key usage encoded in the
// certificates returned by the authority.
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")
)

flag.Parse()

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

if err := validateFlags(*flPKeyPath, *flServerURL); err != nil {
if err := validateFlags(*flPKeyPath, *flServerURL, *flCAFingerprint, *flKeyEnciphermentSelector); err != nil {
fmt.Println(err)
os.Exit(1)
}

caCertsSelector := scep.NopCertsSelector()
if *flCAFingerprint != "" {
switch {
case *flCAFingerprint != "":
hash, err := validateFingerprint(*flCAFingerprint)
if err != nil {
fmt.Printf("invalid fingerprint: %s\n", err)
os.Exit(1)
}
caCertsSelector = scep.FingerprintCertsSelector(fingerprintHashType, hash)
case *flKeyEnciphermentSelector:
caCertsSelector = scep.EnciphermentCertsSelector()
}

dir := filepath.Dir(*flPKeyPath)
Expand Down

0 comments on commit 781f804

Please sign in to comment.