in src/main/java/org/jetbrains/nativecerts/mac/SecurityFrameworkUtil.java [237:366]
public static boolean isTrustedRoot(SecurityFramework.SecCertificateRef certificateRef) {
boolean selfSignedCertificate = isSelfSignedCertificate(getX509Certificate(certificateRef));
CFArrayRefByReference trustedSettingsRef = copyTrustSettings(certificateRef);
CoreFoundation.CFArrayRef trustedSettingsArray = trustedSettingsRef == null ? null : trustedSettingsRef.getArray();
try {
String certificateDescription = CoreFoundationExtUtil.getDescription(certificateRef);
if (trustedSettingsArray == null) {
// Trust record is null we need to verify the certificate first
CoreFoundationExt.Error error = validateCertificate(certificateRef);
if (error == null) {
return true;
} else {
LOGGER.fine("Certificate '" + certificateDescription + "' has no trust settings and failed to validate against trusted roots: " + error);
return false;
}
}
if (LOGGER.isLoggable(Level.FINE)) {
try {
String description = CoreFoundationExtUtil.getDescription(trustedSettingsArray);
LOGGER.fine("Certificate '" + certificateDescription + "' trust settings:\n" + description);
} catch (Throwable t) {
LOGGER.warning(renderExceptionMessage("Unable to describe certificate trusted settings", t));
}
}
if (trustedSettingsArray.getCount() == 0) {
// https://developer.apple.com/documentation/security/1400261-sectrustsettingscopytrustsetting
// An empty trust settings array (that is, the trustSettings parameter returns a valid but empty CFArray) means "always trust this certificate" with an overall trust setting for the certificate of kSecTrustSettingsResultTrustRoot
return true;
}
for (int i = 0; i < trustedSettingsArray.getCount(); i++) {
CoreFoundation.CFDictionaryRef constraints = new CoreFoundation.CFDictionaryRef(trustedSettingsArray.getValueAtIndex(i));
CoreFoundation.CFIndex constraintsCount = CoreFoundationExt.INSTANCE.CFDictionaryGetCount(constraints);
int processedConstrains = 0;
// kSecTrustSettingsResult
{
Pointer value = constraints.getValue(SecurityFramework.kSecTrustSettingsResult);
// from https://developer.apple.com/documentation/security/1400261-sectrustsettingscopytrustsetting
// If this key is not present, a default value of kSecTrustSettingsResultTrustRoot is assumed. Because only a root certificate can have this value, a usage constraints dictionary for a non-root certificate that is missing this key is not valid.
// Note the distinction between the results kSecTrustSettingsResultTrustRoot and kSecTrustSettingsResultTrustAsRoot: The former can only be applied to a root (self-signed) certificates; the latter can only be applied to non-root certificates. Therefore, an empty trust settings array for a non-root certificate is invalid, because the default value of kSecTrustSettingsResultTrustRoot is not valid for a non-root certificate.
SecurityFramework.SecTrustSettingsResult result;
if (value == null) {
result = SecurityFramework.SecTrustSettingsResult.kSecTrustSettingsResultTrustRoot;
} else {
CoreFoundation.CFNumberRef resultNumber = new CoreFoundation.CFNumberRef(value);
result = new SecurityFramework.SecTrustSettingsResult(resultNumber.longValue());
processedConstrains++;
}
// Return only trust roots. Skip even SecurityFramework.SecTrustSettingsResult.kSecTrustSettingsResultTrustAsRoot for now
if (!result.equals(SecurityFramework.SecTrustSettingsResult.kSecTrustSettingsResultTrustRoot)) {
continue;
}
// trust roots must be self-signed, see above
if (!selfSignedCertificate) {
LOGGER.warning("Certificate '" + certificateDescription + "' is not self-signed, skipping");
continue;
}
}
// kSecTrustSettingsAllowedError
{
// Skip kSecTrustSettingsAllowedError processing
// Documentation says "A number which, if encountered during certificate verification, is ignored for that certificate."
// We would not ignore anything, so skip for now
if (constraints.getValue(SecurityFramework.kSecTrustSettingsAllowedError) != null) {
processedConstrains++;
}
}
// kSecTrustSettingsPolicyName
{
// Skip kSecTrustSettingsPolicyName, it does not matter for processing
if (constraints.getValue(SecurityFramework.kSecTrustSettingsPolicyName) != null) {
processedConstrains++;
}
}
// kSecTrustSettingsPolicy
{
Pointer value = constraints.getValue(SecurityFramework.kSecTrustSettingsPolicy);
if (value != null) {
SecurityFramework.SecPolicyRef secPolicyRef = new SecurityFramework.SecPolicyRef(value);
CoreFoundation.CFDictionaryRef policyDictionaryRef = SecurityFramework.INSTANCE.SecPolicyCopyProperties(secPolicyRef);
try {
Pointer policyOid = policyDictionaryRef.getValue(SecurityFramework.kSecPolicyOid);
if (policyOid == null) {
// Must be present, so it's an invalid policy
continue;
}
CoreFoundation.CFStringRef policyOidStringRef = new CoreFoundation.CFStringRef(policyOid);
if (!CoreFoundationExt.INSTANCE.CFEqual(SecurityFramework.kSecPolicyAppleSSL, policyOidStringRef)) {
// Accept only kSecPolicyAppleSSL policy
continue;
}
} finally {
policyDictionaryRef.release();
}
processedConstrains++;
}
}
if (constraintsCount.longValue() == processedConstrains) {
// return only certificates with known and checked constraints attached to them
// this way we'll probably miss some valid trusted roots, but
// there is no way to evaluate other and possibly unknown constraints
return true;
}
}
// No matched constraints => not a trusted root
return false;
} finally {
if (trustedSettingsArray != null) {
trustedSettingsArray.release();
}
}
}