From 1b755888f48d4129997adacc5eded2d7d4a509b3 Mon Sep 17 00:00:00 2001 From: Graham Gilbert Date: Thu, 13 Aug 2020 18:30:27 -0700 Subject: [PATCH] Option to validate only CA and Issuer rather than entire SCEP cert (#700) --- CHANGELOG.md | 196 +++++++++++++++++++++--------------------- cmd/micromdm/serve.go | 56 ++++++------ server/devicecert.go | 85 ++++++++++++++---- server/server.go | 42 ++++----- 4 files changed, 222 insertions(+), 157 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c2ef4d1..1674e8a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,21 +1,25 @@ +## [v1.8.0](https://github.com/micromdm/micromdm/compare/v1.7.1...master) TBD + +- Add `-validate-scep-issuer` and `-validate-scep-expiration` flags to only validate the SCEP certificate was issued by the MicrMDM SCEP CA, and optionally to validate that the certificate hasn't expired (#700) + ## [v1.7.1](https://github.com/micromdm/micromdm/compare/v1.6.0...v1.7.1) April, 2020 -* Replace un-maintained UUID dependency #665 +- Replace un-maintained UUID dependency #665 ## [v1.7.0](https://github.com/micromdm/micromdm/compare/v1.6.0...v1.7.0-alpha) March, 2020 ### Reliability, scalability, security, and usability improvements: -* Add device DEP status to API response (#617) -* CLI improvements (#618, #620, #621) -* Support new values for AccountConfiguration (#627) -* Fix issue where DEP watcher would stop permanently for transient network issues (#582, #632) -* Workaround issue where a newly added DEP token would not be used after a restart (#546, #633) -* Fix bug with applying an empty blueprint (#615, #634) -* Add `-no-command-history` flag to disable saving of command history (#640). This works around a race-condition/scalability issue with device records (#556). -* Add dynamic SCEP challenges (#642). Require dynamic SCEP challenges for certificate issuance with `-use-dynamic-challenge` and (only recommended for testing) generate them in enrollment profiles with `-gen-dynamic-challenge`. -* Add MDM commands to enable and disable remote desktop (#651) -* SCEP payload key names were corrected (#652) +- Add device DEP status to API response (#617) +- CLI improvements (#618, #620, #621) +- Support new values for AccountConfiguration (#627) +- Fix issue where DEP watcher would stop permanently for transient network issues (#582, #632) +- Workaround issue where a newly added DEP token would not be used after a restart (#546, #633) +- Fix bug with applying an empty blueprint (#615, #634) +- Add `-no-command-history` flag to disable saving of command history (#640). This works around a race-condition/scalability issue with device records (#556). +- Add dynamic SCEP challenges (#642). Require dynamic SCEP challenges for certificate issuance with `-use-dynamic-challenge` and (only recommended for testing) generate them in enrollment profiles with `-gen-dynamic-challenge`. +- Add MDM commands to enable and disable remote desktop (#651) +- SCEP payload key names were corrected (#652) Thanks to our contributors for this release: @grahamgilbert, @n8felton, @tomaswallentinus @@ -23,30 +27,30 @@ Thanks to our contributors for this release: @grahamgilbert, @n8felton, @tomaswa ### Go security update along with updates: -* Add `erase_device` tools script -* Add assign profile endpoint (#611) -* Add support for User Enrollment (#597) -* Add support for Signing Profiles (#602) -* Add support for setting APNS message expiration (#609) -* Update `mdmctl remove devices -serial` flag to be plural (now `-serials`) (#621) +- Add `erase_device` tools script +- Add assign profile endpoint (#611) +- Add support for User Enrollment (#597) +- Add support for Signing Profiles (#602) +- Add support for setting APNS message expiration (#609) +- Update `mdmctl remove devices -serial` flag to be plural (now `-serials`) (#621) Thanks to our contributors for this release: @WardsParadox, @n8felton ## [v1.5.0](https://github.com/micromdm/micromdm/compare/v1.4.0...v1.5.0) June 15 2019 -* Fix DEP token update issue (#513, #510) -* Refactor certificate verification and implement UDID-cert authentication (#358, #429) -* Cleanup DEP library and integrate into main project (#504, #505) -* Add API endpoint to retrieve APNS certificate (#503) -* Remove deprecated `-apns` flags from server startup (#528) -* Move API calls to list endpoints from HTTP GET to HTTP POST (#522, #523, #524, #525, #526) -* Add support for the ApplicationConfiguration Setting (#521) -* Add support for the ActivationLockBypassCode Command (#578) -* Allow SCEP client validity to be adjusted via server startup flag (#577) -* Fix bug in mdmctl server saving, switch config when saving automatically (#565, #566) -* Do not send DeviceConfigured automatically when there are no blueprints (#586) -* Set acknowledge time when moving command to completed queue (#581) -* Serialize PurchaseMethod when value is 0. (#592) +- Fix DEP token update issue (#513, #510) +- Refactor certificate verification and implement UDID-cert authentication (#358, #429) +- Cleanup DEP library and integrate into main project (#504, #505) +- Add API endpoint to retrieve APNS certificate (#503) +- Remove deprecated `-apns` flags from server startup (#528) +- Move API calls to list endpoints from HTTP GET to HTTP POST (#522, #523, #524, #525, #526) +- Add support for the ApplicationConfiguration Setting (#521) +- Add support for the ActivationLockBypassCode Command (#578) +- Allow SCEP client validity to be adjusted via server startup flag (#577) +- Fix bug in mdmctl server saving, switch config when saving automatically (#565, #566) +- Do not send DeviceConfigured automatically when there are no blueprints (#586) +- Set acknowledge time when moving command to completed queue (#581) +- Serialize PurchaseMethod when value is 0. (#592) Thanks to our contributors for this release: @discentem, @nkllkc, @arubdesu, @bdemetris, @Lepidopteron, @joncrain, @emman27, @jenjac, @daniellockard, and @0xflotus @@ -54,89 +58,89 @@ Thanks to our contributors for this release: @discentem, @nkllkc, @arubdesu, @bd ### Stability Improvements -* Handle DEP INVALID_CURSOR response (#497) -* Use config for block push (#479, #480) -* No longer store SCEP CA on disk or include in enrollment profile (#490) -* Further SCEP fixes (#492, #493) -* Base64 fixes for API CLI tools (#477) -* `mdmctl apply block` now works with self-signed certs (#480) -* Add API CLI tool for dep sync (#481) -* DeviceInformation command API example support query strings (#469) -* Allow setting curl options in environment variable (#455) -* Fix URL params decoding. (#467) -* Reorganize/refactor server init (#458) -* Allow supplying additional `curl` options in API CLI tools (#455) +- Handle DEP INVALID_CURSOR response (#497) +- Use config for block push (#479, #480) +- No longer store SCEP CA on disk or include in enrollment profile (#490) +- Further SCEP fixes (#492, #493) +- Base64 fixes for API CLI tools (#477) +- `mdmctl apply block` now works with self-signed certs (#480) +- Add API CLI tool for dep sync (#481) +- DeviceInformation command API example support query strings (#469) +- Allow setting curl options in environment variable (#455) +- Fix URL params decoding. (#467) +- Reorganize/refactor server init (#458) +- Allow supplying additional `curl` options in API CLI tools (#455) Thanks to our contributors for this release: @erikng, @gerardkok, @knightsc, @marpaia, and @ochimo! ## [v1.3.1](https://github.com/micromdm/micromdm/compare/v1.3.0...v1.3.1) July 10 2018 -* Update base container to Alpine 3.7 (#437) -* Fix bugs in SCEP enrollment (#451) -* Fix issue with APNS timeouts -- Issue #215 (#446) -* Add device_information and security_info commands with curl API (#448) -* Add support for InstallEnterpriseApplication command (#452) +- Update base container to Alpine 3.7 (#437) +- Fix bugs in SCEP enrollment (#451) +- Fix issue with APNS timeouts -- Issue #215 (#446) +- Add device_information and security_info commands with curl API (#448) +- Add support for InstallEnterpriseApplication command (#452) ## [v1.3.0](https://github.com/micromdm/micromdm/compare/v1.2.0...v1.3.0) ### Auto-assigner -* Reorganize/refactor MDM, device, webhook services. #423, #424, #425, #426, #427 -* Do not allow `mdmctl config set` without args. #421 -* Fix for multiple UDID records. #422 -* Added/refactored logging. #405, #425 -* Added `-homepage` switch. #420 -* Warn about deprecated APNS switches. #412 -* Disallow bad TLS configuration with `-tls=false`. #414 -* Refactored MDM types. #341, #415 -* Added DEP auto-assigner feature. #405 -* Fixed bug with authentication error messages. #411 -* Added support for querying devices by serial(s). #363 -* Added support for triggering a DEP sync via API. #404 -* Added support for mdmcert.download directly to `mdmctl` #401 -* Reject network MDM user attempts until we add support. #379 -* Warn when starting without an API key. #396 -* Added tools and documentation for ngrok, curl, and APIs. #392 -* Fix issue with MDM command `AvailableOSUpdates` parsing. #368 -* Validate APNs Push Certificate Topic. #373 -* `mdmctl` now outputs to stdout vs. stderr. #360 -* Added common HTTP library `httputil`. #350 -* Added project Code of Conduct. #334 -* Refactored services (mostly for HA). #348, #349, #351, #352, #353, #354, #355, #359 -* Reorganized project layout. #333, #335, #336, #338, #340, #347 -* Added support for version API. #327 -* Added command response webhook feature. #315 -* Added support for supplied `depsim` URL. #318 -* Added Dockerfile. #316 +- Reorganize/refactor MDM, device, webhook services. #423, #424, #425, #426, #427 +- Do not allow `mdmctl config set` without args. #421 +- Fix for multiple UDID records. #422 +- Added/refactored logging. #405, #425 +- Added `-homepage` switch. #420 +- Warn about deprecated APNS switches. #412 +- Disallow bad TLS configuration with `-tls=false`. #414 +- Refactored MDM types. #341, #415 +- Added DEP auto-assigner feature. #405 +- Fixed bug with authentication error messages. #411 +- Added support for querying devices by serial(s). #363 +- Added support for triggering a DEP sync via API. #404 +- Added support for mdmcert.download directly to `mdmctl` #401 +- Reject network MDM user attempts until we add support. #379 +- Warn when starting without an API key. #396 +- Added tools and documentation for ngrok, curl, and APIs. #392 +- Fix issue with MDM command `AvailableOSUpdates` parsing. #368 +- Validate APNs Push Certificate Topic. #373 +- `mdmctl` now outputs to stdout vs. stderr. #360 +- Added common HTTP library `httputil`. #350 +- Added project Code of Conduct. #334 +- Refactored services (mostly for HA). #348, #349, #351, #352, #353, #354, #355, #359 +- Reorganized project layout. #333, #335, #336, #338, #340, #347 +- Added support for version API. #327 +- Added command response webhook feature. #315 +- Added support for supplied `depsim` URL. #318 +- Added Dockerfile. #316 ## [v1.2.0](https://github.com/micromdm/micromdm/compare/v1.1.0...v1.2.0) October 31 2017 ### User Profiles -* Added support for modifying the default enrollment profile. -* Added support for user level profiles. -* Added support for AccountConfiguration during DEP Enrollment. Specified in blueprints -* Addes support for multiple server configs in `mdmctl`. -* Added `mdmctl mdmcert upload` command which uploads/replaces the servers push certificate. -* Incorporated certhelper into mdmctl. See `mdmctl mdmcert -h` -* Added ENV variables for sensitive flags: `MICROMDM_APNS_KEY_PASSWORD`,`MICROMDM_API_KEY` -* Removed the `-redir-addr` flag. Redirect to HTTPS is only enabled when the 443 port is used. +- Added support for modifying the default enrollment profile. +- Added support for user level profiles. +- Added support for AccountConfiguration during DEP Enrollment. Specified in blueprints +- Addes support for multiple server configs in `mdmctl`. +- Added `mdmctl mdmcert upload` command which uploads/replaces the servers push certificate. +- Incorporated certhelper into mdmctl. See `mdmctl mdmcert -h` +- Added ENV variables for sensitive flags: `MICROMDM_APNS_KEY_PASSWORD`,`MICROMDM_API_KEY` +- Removed the `-redir-addr` flag. Redirect to HTTPS is only enabled when the 443 port is used. ## [v1.1.0](https://github.com/micromdm/micromdm/compare/v1.0.0...v1.1.0) June 05 2017 ### YVR! -* Import and sign pkgs, generate appmanifest on import. -* Support syncing devices from DEP when token is added. -* Option to include SSL certificates in DEP profile template (-anchor and -use-server-cert) #107 -* /push and /v1/commands API endpoints require API authentication #157 -* Add `mdmctl` binary for interacting with the server over API. #127 -* Save DEP cursor for use after restart. #109 -* Add `-examples` flag to micromdm serve. #119 -* Add HTTP logger (with apache format) for all endpoints. #85 -* Serve a basic homepage at `/`. #113 -* Decrypt armored private keys if the `-apns-password` flag is specified by the user. #105 -* Improved command queue handling of NotNow and other responses. #96 -* Fixed bug that allowed for duplicate device records on re-enrollment. #125 -* Fixed data race in pubsub package. #97 -* Fixed bug that would cause PushInfo Token for the device to be replaced by one for the user. #90 +- Import and sign pkgs, generate appmanifest on import. +- Support syncing devices from DEP when token is added. +- Option to include SSL certificates in DEP profile template (-anchor and -use-server-cert) #107 +- /push and /v1/commands API endpoints require API authentication #157 +- Add `mdmctl` binary for interacting with the server over API. #127 +- Save DEP cursor for use after restart. #109 +- Add `-examples` flag to micromdm serve. #119 +- Add HTTP logger (with apache format) for all endpoints. #85 +- Serve a basic homepage at `/`. #113 +- Decrypt armored private keys if the `-apns-password` flag is specified by the user. #105 +- Improved command queue handling of NotNow and other responses. #96 +- Fixed bug that allowed for duplicate device records on re-enrollment. #125 +- Fixed data race in pubsub package. #97 +- Fixed bug that would cause PushInfo Token for the device to be replaced by one for the user. #90 diff --git a/cmd/micromdm/serve.go b/cmd/micromdm/serve.go index 7ffc9e64..6db3e519 100644 --- a/cmd/micromdm/serve.go +++ b/cmd/micromdm/serve.go @@ -70,24 +70,26 @@ const homePage = ` func serve(args []string) error { flagset := flag.NewFlagSet("serve", flag.ExitOnError) var ( - flConfigPath = flagset.String("config-path", env.String("MICROMDM_CONFIG_PATH", "/var/db/micromdm"), "Path to configuration directory") - flServerURL = flagset.String("server-url", env.String("MICROMDM_SERVER_URL", ""), "Public HTTPS url of your server") - flAPIKey = flagset.String("api-key", env.String("MICROMDM_API_KEY", ""), "API Token for mdmctl command") - flTLS = flagset.Bool("tls", env.Bool("MICROMDM_TLS", true), "Use https") - flTLSCert = flagset.String("tls-cert", env.String("MICROMDM_TLS_CERT", ""), "Path to TLS certificate") - flTLSKey = flagset.String("tls-key", env.String("MICROMDM_TLS_KEY", ""), "Path to TLS private key") - flHTTPAddr = flagset.String("http-addr", env.String("MICROMDM_HTTP_ADDR", ":https"), "http(s) listen address of mdm server. defaults to :8080 if tls is false") - flHTTPDebug = flagset.Bool("http-debug", env.Bool("MICROMDM_HTTP_DEBUG", false), "Enable debug for http(dumps full request)") - flRepoPath = flagset.String("filerepo", env.String("MICROMDM_FILE_REPO", ""), "Path to http file repo") - flDepSim = flagset.String("depsim", env.String("MICROMDM_DEPSIM_URL", ""), "Use depsim URL") - flExamples = flagset.Bool("examples", false, "Prints some example usage") - flCommandWebhookURL = flagset.String("command-webhook-url", env.String("MICROMDM_WEBHOOK_URL", ""), "URL to send command responses") - flHomePage = flagset.Bool("homepage", env.Bool("MICROMDM_HTTP_HOMEPAGE", true), "Hosts a simple built-in webpage at the / address") - flSCEPClientValidity = flagset.Int("scep-client-validity", env.Int("MICROMDM_SCEP_CLIENT_VALIDITY", 365), "Sets the scep certificate validity in days") - flNoCmdHistory = flagset.Bool("no-command-history", env.Bool("MICROMDM_NO_COMMAND_HISTORY", false), "disables saving of command history") - flUseDynChallenge = flagset.Bool("use-dynamic-challenge", env.Bool("MICROMDM_USE_DYNAMIC_CHALLENGE", false), "require dynamic SCEP challenges") - flGenDynChalEnroll = flagset.Bool("gen-dynamic-challenge", env.Bool("MICROMDM_GEN_DYNAMIC_CHALLENGE", false), "generate dynamic SCEP challenges in enrollment profile (built-in only)") - flPrintArgs = flagset.Bool("print-flags", false, "Print all flags and their values") + flConfigPath = flagset.String("config-path", env.String("MICROMDM_CONFIG_PATH", "/var/db/micromdm"), "Path to configuration directory") + flServerURL = flagset.String("server-url", env.String("MICROMDM_SERVER_URL", ""), "Public HTTPS url of your server") + flAPIKey = flagset.String("api-key", env.String("MICROMDM_API_KEY", ""), "API Token for mdmctl command") + flTLS = flagset.Bool("tls", env.Bool("MICROMDM_TLS", true), "Use https") + flTLSCert = flagset.String("tls-cert", env.String("MICROMDM_TLS_CERT", ""), "Path to TLS certificate") + flTLSKey = flagset.String("tls-key", env.String("MICROMDM_TLS_KEY", ""), "Path to TLS private key") + flHTTPAddr = flagset.String("http-addr", env.String("MICROMDM_HTTP_ADDR", ":https"), "http(s) listen address of mdm server. defaults to :8080 if tls is false") + flHTTPDebug = flagset.Bool("http-debug", env.Bool("MICROMDM_HTTP_DEBUG", false), "Enable debug for http(dumps full request)") + flRepoPath = flagset.String("filerepo", env.String("MICROMDM_FILE_REPO", ""), "Path to http file repo") + flDepSim = flagset.String("depsim", env.String("MICROMDM_DEPSIM_URL", ""), "Use depsim URL") + flExamples = flagset.Bool("examples", false, "Prints some example usage") + flCommandWebhookURL = flagset.String("command-webhook-url", env.String("MICROMDM_WEBHOOK_URL", ""), "URL to send command responses") + flHomePage = flagset.Bool("homepage", env.Bool("MICROMDM_HTTP_HOMEPAGE", true), "Hosts a simple built-in webpage at the / address") + flSCEPClientValidity = flagset.Int("scep-client-validity", env.Int("MICROMDM_SCEP_CLIENT_VALIDITY", 365), "Sets the scep certificate validity in days") + flNoCmdHistory = flagset.Bool("no-command-history", env.Bool("MICROMDM_NO_COMMAND_HISTORY", false), "disables saving of command history") + flUseDynChallenge = flagset.Bool("use-dynamic-challenge", env.Bool("MICROMDM_USE_DYNAMIC_CHALLENGE", false), "require dynamic SCEP challenges") + flGenDynChalEnroll = flagset.Bool("gen-dynamic-challenge", env.Bool("MICROMDM_GEN_DYNAMIC_CHALLENGE", false), "generate dynamic SCEP challenges in enrollment profile (built-in only)") + flValidateSCEPIssuer = flagset.Bool("validate-scep-issuer", env.Bool("MICROMDM_VALIDATE_SCEP_ISSUER", false), "validate only the issuer of the SCEP certificate rather than the whole certificate") + flValidateSCEPExpiration = flagset.Bool("validate-scep-expiration", env.Bool("MICROMDM_VALIDATE_SCEP_EXPIRATION", false), "validate that the SCEP certificate is still valid") + flPrintArgs = flagset.Bool("print-flags", false, "Print all flags and their values") ) flagset.Usage = usageFor(flagset, "micromdm serve [flags]") if err := flagset.Parse(args); err != nil { @@ -124,14 +126,16 @@ func serve(args []string) error { return errors.Wrapf(err, "creating config directory %s", *flConfigPath) } sm := &server.Server{ - ConfigPath: *flConfigPath, - ServerPublicURL: strings.TrimRight(*flServerURL, "/"), - Depsim: *flDepSim, - TLSCertPath: *flTLSCert, - CommandWebhookURL: *flCommandWebhookURL, - NoCmdHistory: *flNoCmdHistory, - UseDynSCEPChallenge: *flUseDynChallenge, - GenDynSCEPChallenge: *flGenDynChalEnroll, + ConfigPath: *flConfigPath, + ServerPublicURL: strings.TrimRight(*flServerURL, "/"), + Depsim: *flDepSim, + TLSCertPath: *flTLSCert, + CommandWebhookURL: *flCommandWebhookURL, + NoCmdHistory: *flNoCmdHistory, + UseDynSCEPChallenge: *flUseDynChallenge, + GenDynSCEPChallenge: *flGenDynChalEnroll, + ValidateSCEPIssuer: *flValidateSCEPIssuer, + ValidateSCEPExpiration: *flValidateSCEPExpiration, WebhooksHTTPClient: &http.Client{Timeout: time.Second * 30}, diff --git a/server/devicecert.go b/server/devicecert.go index 277ffe22..3e64b6ee 100644 --- a/server/devicecert.go +++ b/server/devicecert.go @@ -2,7 +2,9 @@ package server import ( "context" + "crypto/rsa" "crypto/x509" + "time" "github.com/go-kit/kit/log" "github.com/go-kit/kit/log/level" @@ -12,23 +14,59 @@ import ( ) type ScepVerifyDepot interface { + CA(pass []byte) ([]*x509.Certificate, *rsa.PrivateKey, error) HasCN(cn string, allowTime int, cert *x509.Certificate, revokeOldCertificate bool) (bool, error) } -func VerifyCertificateMiddleware(store ScepVerifyDepot, logger log.Logger) mdm.Middleware { +func VerifyCertificateMiddleware(validateSCEPIssuer bool, validateSCEPExpiration bool, store ScepVerifyDepot, logger log.Logger) mdm.Middleware { return func(next mdm.Service) mdm.Service { return &verifyCertificateMiddleware{ - store: store, - next: next, - logger: logger, + store: store, + next: next, + logger: logger, + validateSCEPIssuer: validateSCEPIssuer, + validateSCEPExpiration: validateSCEPExpiration, } } } type verifyCertificateMiddleware struct { - store ScepVerifyDepot - next mdm.Service - logger log.Logger + store ScepVerifyDepot + next mdm.Service + logger log.Logger + validateSCEPIssuer bool + validateSCEPExpiration bool +} + +func (mw *verifyCertificateMiddleware) verifyIssuer(devcert *x509.Certificate) error { + if mw.validateSCEPExpiration { + expiration := devcert.NotAfter + if time.Now().After(expiration) { + return errors.New("device certificate is expired") + } + } + ca, _, err := mw.store.CA(nil) + if err != nil { + return errors.Wrap(err, "error retrieving CA") + } + + roots := x509.NewCertPool() + for _, cert := range ca { + roots.AddCert(cert) + } + + opts := x509.VerifyOptions{ + Roots: roots, + KeyUsages: []x509.ExtKeyUsage{ + x509.ExtKeyUsageAny, + }, + } + + if _, err := devcert.Verify(opts); err != nil { + return errors.Wrap(err, "error verifying certificate") + } + + return nil } func (mw *verifyCertificateMiddleware) Acknowledge(ctx context.Context, req mdm.AcknowledgeEvent) ([]byte, error) { @@ -40,11 +78,21 @@ func (mw *verifyCertificateMiddleware) Acknowledge(ctx context.Context, req mdm. if err != nil { return nil, errors.Wrap(err, "error checking device certificate") } - if !hasCN { - err := errors.New("unauthorized client") - level.Info(mw.logger).Log("err", err) - return nil, err + + unauth_err := errors.New("unauthorized client") + if !hasCN && !mw.validateSCEPIssuer { + _ = level.Info(mw.logger).Log("err", unauth_err, "issuer", devcert.Issuer.String(), "expiration", devcert.NotAfter) + return nil, unauth_err } + + if !hasCN && mw.validateSCEPIssuer { + err := mw.verifyIssuer(devcert) + if err != nil { + _ = level.Info(mw.logger).Log("err", err, "issuer", devcert.Issuer.String(), "expiration", devcert.NotAfter) + return nil, unauth_err + } + } + return mw.next.Acknowledge(ctx, req) } @@ -57,10 +105,17 @@ func (mw *verifyCertificateMiddleware) Checkin(ctx context.Context, req mdm.Chec if err != nil { return errors.Wrap(err, "error checking device certificate") } - if !hasCN { - err := errors.New("unauthorized client") - level.Info(mw.logger).Log("err", err) - return err + unauth_err := errors.New("unauthorized client") + if !hasCN && !mw.validateSCEPIssuer { + _ = level.Info(mw.logger).Log("err", unauth_err, "issuer", devcert.Issuer.String(), "expiration", devcert.NotAfter) + return unauth_err + } + if !hasCN && mw.validateSCEPIssuer { + err := mw.verifyIssuer(devcert) + if err != nil { + _ = level.Info(mw.logger).Log("err", err, "issuer", devcert.Issuer.String(), "expiration", devcert.NotAfter) + return unauth_err + } } return mw.next.Checkin(ctx, req) } diff --git a/server/server.go b/server/server.go index 59f736b9..0da2f360 100644 --- a/server/server.go +++ b/server/server.go @@ -39,25 +39,27 @@ import ( ) type Server struct { - ConfigPath string - Depsim string - PubClient pubsub.PublishSubscriber - DB *bolt.DB - ServerPublicURL string - SCEPChallenge string - SCEPClientValidity int - TLSCertPath string - SCEPDepot *boltdepot.Depot - UseDynSCEPChallenge bool - GenDynSCEPChallenge bool - SCEPChallengeDepot *challengestore.Depot - ProfileDB profile.Store - ConfigDB config.Store - RemoveDB block.Store - CommandWebhookURL string - DEPClient *dep.Client - SyncDB *syncbuiltin.DB - NoCmdHistory bool + ConfigPath string + Depsim string + PubClient pubsub.PublishSubscriber + DB *bolt.DB + ServerPublicURL string + SCEPChallenge string + SCEPClientValidity int + TLSCertPath string + SCEPDepot *boltdepot.Depot + UseDynSCEPChallenge bool + GenDynSCEPChallenge bool + SCEPChallengeDepot *challengestore.Depot + ProfileDB profile.Store + ConfigDB config.Store + RemoveDB block.Store + CommandWebhookURL string + DEPClient *dep.Client + SyncDB *syncbuiltin.DB + NoCmdHistory bool + ValidateSCEPIssuer bool + ValidateSCEPExpiration bool APNSPushService apns.Service CommandService command.Service @@ -186,7 +188,7 @@ func (c *Server) setupCommandQueue(logger log.Logger) error { mdmService = device.UDIDCertAuthMiddleware(devDB, udidauthLogger)(mdmService) verifycertLogger := log.With(logger, "component", "verifycert") - mdmService = VerifyCertificateMiddleware(c.SCEPDepot, verifycertLogger)(mdmService) + mdmService = VerifyCertificateMiddleware(c.ValidateSCEPIssuer, c.ValidateSCEPExpiration, c.SCEPDepot, verifycertLogger)(mdmService) } c.MDMService = mdmService