Skip to main content
Jamf Nation, hosted by Jamf, is a knowledgeable community of Apple-focused admins and Jamf users. Join us in person at the ninth annual Jamf Nation User Conference (JNUC) this November for three days of learning, laughter and IT love.

intermittent client error when prompting for enrolment - unexpected status (403)

Hi all,

I'm in the process of getting our legacy systems enroled into Jamf Pro and a number of them (around 10% at this stage) are getting an error "Device Enrolment" installation failed.
The MDM server for your organisation returned an unexpected status (403)

From a brief search it appears that deleting /Library/Keychains/apsd.keychain and re-booting will fix the issue but given I want to enrol ~6-800 devices this way, actioning 10-15% of those by hand could be tedious.

Taking a look at the server logs I can see these entries which started occurring the same time as I kicked off the enrolment nag.

2019-04-03 05:45:01,290 [ERROR] [lina-exec-6] [dEnrollmentIssuerVerifier] - Unable to validate issuer
java.security.cert.CertPathBuilderException: Certification path could not be validated.
    at org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi.engineBuild(Unknown Source)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:280)
    at com.jamfsoftware.jss.utils.security.CloudEnrollmentIssuerVerifier.isIssuerValid(CloudEnrollmentIssuerVerifier.java:64)
    at com.jamfsoftware.jss.utils.SecurityUtils.isIssuerValid(SecurityUtils.java:349)
    at com.jamfsoftware.jss.utils.SecurityUtils.validateCMSSignature(SecurityUtils.java:272)
    at com.jamfsoftware.jss.utils.SecurityUtils.verifySignatureForEnrollment(SecurityUtils.java:338)
    at com.jamfsoftware.jss.frontend.enrollment.configurator.ConfiguratorEnrollmentStep.isSignatureLegit(ConfiguratorEnrollmentStep.java:160)
    at com.jamfsoftware.jss.frontend.enrollment.cloud.DEPEnrollmentStep.shouldProcessStep(DEPEnrollmentStep.java:61)
    at com.jamfsoftware.jss.frontend.enrollment.ota.OTAEnrollmentController.doProcess(OTAEnrollmentController.java:97)
    at com.jamfsoftware.jss.frontend.enrollment.ota.OTAEnrollmentController.doPost(OTAEnrollmentController.java:75)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:648)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:292)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at com.jamfsoftware.jss.frontend.streamlinedenrollment.CloudEnrollmentFilter.doFilter(CloudEnrollmentFilter.java:39)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at com.jamfsoftware.jss.frontend.JSSLoadingFilter.doFilter(JSSLoadingFilter.java:209)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:213)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:106)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:494)
    at org.apache.catalina.valves.SemaphoreValve.invoke(SemaphoreValve.java:167)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
    at org.apache.catalina.valves.StuckThreadDetectionValve.invoke(StuckThreadDetectionValve.java:208)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:616)
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:676)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:522)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1095)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:672)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1520)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1476)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Thread.java:748)
Caused by: org.bouncycastle.jce.exception.ExtCertPathValidatorException: Could not validate certificate: certificate expired on 20180922043724GMT+00:00
    at org.bouncycastle.jce.provider.RFC3280CertPathUtilities.processCertA(Unknown Source)
    at org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi.engineValidate(Unknown Source)
    at java.security.cert.CertPathValidator.validate(CertPathValidator.java:292)
    at org.bouncycastle.jce.provider.PKIXCertPathBuilderSpi.build(Unknown Source)
    ... 42 more
Caused by: java.security.cert.CertificateExpiredException: certificate expired on 20180922043724GMT+00:00
    at org.bouncycastle.jce.provider.X509CertificateObject.checkValidity(Unknown Source)
    ... 46 more
2019-04-03 05:45:01,299 [WARN ] [lina-exec-6] [DEPEnrollmentStep        ] - Processing device rejection: FAILED_SIGNATURE_CHECK
2019-04-03 05:45:01,299 [ERROR] [lina-exec-6] [onfiguratorEnrollmentStep] - Unable to process signature for enrollment request

I'm thinking this means there is a certificate inside apsd.keychain which is expired and this is why the devices are having issue communicating. Does anyone know of a way to detect or get macOS to refresh these certificates without requiring a reboot? There (so far) doesn't appear to be any obvious combination of hardware, OS version or other software I can check against.

Also, is there a way to match up the above server log with an endpoint (IP address) - I'm running on jamfcloud otherwise I'd triangulate with the apache logs or other access logs but I don't think I have access to those.

New devices, fresh built devices, new OS installs and at least 85% of existing devices don't have an issue at all. Just seems to be a significant handful with the issue.

Like Comment
Order by:
SOLVED Posted: by bartreardon

security dump-keychain /Library/Keychains/apsd.keychain gets me some info I might be able to check

update:

/usr/bin/security find-certificate -a -p -Z /Library/Keychains/apsd.keychain | /usr/bin/openssl x509 -noout -enddate| cut -f2 -d=

will get me the expiry date of the apsd certificate - if it's expired, then I can avoid initiating the DEP nag on that device

update 2:
The following script can be used to detect if the certificate in apsd.keychain is valid or not

#!/bin/bash

KEYCHAIN="/Library/Keychains/apsd.keychain"
DATENOW=$(date "+%Y%m%d")

if [ -e ${KEYCHAIN} ]; then  
    CERTDATA=$(/usr/bin/security find-certificate -a -p -Z ${KEYCHAIN})
    CERTEXPDATE=$(echo "${CERTDATA}" | /usr/bin/openssl x509 -noout -enddate| cut -f2 -d=)
    CERTDATECMP=$(date -j -f "%b %d %T %Y %Z" "${CERTEXPDATE}" "+%Y%m%d")

    echo "CERTDATA    = ${CERTDATA}"
    echo "CERTEXPDATE = ${CERTEXPDATE}"
    echo "CERTDATECMP = ${CERTDATECMP}"

    if [[ ${DATENOW} -ge ${CERTDATECMP} ]]; then
        echo "apsd keychain certificate EXPIRED"
    else
        echo "apsd keychain certificate VALID"
    fi
else
    echo "Could not find ${KEYCHAIN}"
fi
Like
SOLVED Posted: by bartreardon

So thank you to Jesse Peterson over on slack for finding this

MDM spec here https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/iPhoneOTAConfiguration/profile-service/profile-service.html#//apple_ref/doc/uid/TP40009505-CH2-SW4

with this little tidbit:

WARNING:  When device certificates signed “Apple iPhone Device CA” are evaluated their validity dates should be ignored.

so Jamf is being good for checking certificate validity but is actually not following the MDM spec by doing so - also Apple for advising certificate validity checks should be ignored ಠ_ಠ

I'm pretty confident Apple aren't going to change and a bugfix from Jamf probably won't happen in time for me to continue the rollout, but, at least I know what's going on now so I can work around it.

Like