Mailing Lists: Apple Mailing Lists
Image of Mac OS face in stamp
Re: Trouble getting trust settings to stick
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Trouble getting trust settings to stick




On Oct 13, 2008, at 11:36 AM, Rich Siegel wrote:

I'm dusting off some ancient SecurityHI code; way back when I wrote it,
it had to run on 10.3 and there were bugs in that OS that prevented
SecEditTrust() from working.

Hi Rich,

First off, if this is new code being written for 10.4+, I would try to use SFCertificateTrustPanel instead. SecEditTrust() is part of a frozen, dusty SecurityHI bridge layer to support Carbon access to native Cocoa UI. It was always intended to be a temporary measure to allow developers time to move from Carbon to Cocoa, and has various limitations not present in the Cocoa UI (such as the one where you don't get a Cancel button in that dialog.) Our recommendation has always been to use the SecurityInterface framework APIs (Objective-C) for certificate UI.

Consider a certificate from the server "mail.example.com" (note
fabricated domain name). It's self-signed (no trusted root) and expired,
and the server name mismatches: the cert is signed for "example.com",
not "mail.example.com"

[...code removed...]

One problem with your code is that you are treating kSecTrustResultUnspecified as an untrusted case. In fact, it's the one case that means the certificate *is* trusted, all by itself, without user trust settings having been specified. (If user trust settings were specified, then you get a kSecTrustResultProceed or kSecTrustResultDeny result instead.)

Here's how you should group the SecTrustEvaluate result cases:

case kSecTrustResultConfirm:
case kSecTrustResultRecoverableTrustFailure:
{
// the certificate itself is OK, but it's not trusted (i.e. it has failed the requirements of the policy being evaluated);
// must ask the user if it's OK to use this certificate anyway
if (PutUpTrustPanelAndUserClickedOKButton())
GoAhead(...);
else
Fail(...);
break;
}


case kSecTrustResultUnspecified:
case kSecTrustResultProceed:
{
// the certificate is trusted (implicitly, in the former case; explicitly via user trust settings in the latter)
GoAhead(...);
break;
}


                case kSecTrustResultInvalid:
                case kSecTrustResultDeny:
                case kSecTrustResultFatalTrustFailure:
                case kSecTrustResultOtherError:
		{
			// the certificate is either explicitly not trusted (Deny),
			// or is otherwise unable to be used
			Fail(...);
			break;
		}

The first time I run this code, I get the SecEditTrust() dialog. There's
a check box to 'Always trust "example.com" when connecting to
"mail.example.com".' If I turn this on and click "Continue", I end up
getting the SecEditTrust() dialog once more. On the second invocation,
the icon next to the certificate name has a blue "+" overlaid,
indicating "This certificate is marked as trusted for this account." The
check box title has changed to "Always trust these certificates" and is
turned off. In between there are various prompts for my login password,
to authenticate certificate and keychain changes.

The "2 attempts to get a certificate marked as trusted" issue is a known Leopard bug, which is fixed in an upcoming 10.5.x update.


(You're evidently running Leopard since you are seeing the blue "+" badge, indicating that there are user trust settings on this certificate. On Tiger, user trust settings are advisory only... you can check them yourself with SecTrustGetUserTrust if you get a kSecTrustResultRecoverableTrustFailure result, but they do *not* affect the outcome of a SecTrustEvaluate call as they will on Leopard.)

Despite all of this, however, the decisions I make in the dialogs don't
stick: if I attempt a new connection to the same server, whether or not
I quit and relaunch the application in between, I have to go through the
same dance every time. I was expecting that checking "Always trust..."
would cause that certificate to be unconditionally accepted for
connections to that server, no matter what. Is there a technical reason
that user trust decisions aren't persisting, or have I written (or
encountered) a bug?

You've likely encountered a bug. Almost all of the "trust settings don't stick" bug reports we've seen fall into two groups:


1. If more than one app is running and has changed trust settings via this UI in a given login session, one of them may have grabbed a lock on the helper tool (kcproxy) which is used to change the trust settings. If you see messages in your syslog which say, "Couldn't register server "com.apple.KeychainProxyServer" on this host" then you are hitting this bug. The workaround is to quit any other apps which have put up the trust UI, then try again.

2. If your mail server is hosting more than one virtual domain (and does not present a separate certificate for each), such that successive connections to "mail.example.com" and "mail.another- different-example.com" both resolve to the same server presenting the same certificate for "example.com", then there is a known bug where clicking the "Always trust <certificate> when connecting to <host>" checkbox will overwrite previous trust settings for that certificate with the current value of <host>, instead of appending it.

Note that the "always trust" checkbox has a couple of behaviors. First, it will try to add the certificate to a keychain if isn't already there. Self-signed root certificates are added to the System keychain; non-roots are added to the user's default keychain. Additionally, trust exceptions are applied which allow the certificate to be expired or have a hostname mismatch when going to a particular host. Since "add certificate to keychain" and "change trust settings on certificate" are separate operations, they may each require authentication. (We've mostly got that down to just one dialog now.)

You can use the /usr/bin/security tool to dump a list of your current trust settings (on Leopard and later). As an example, I clicked the "Always trust..." checkbox on a certificate presented by an internal web server, "clockwork.apple.com". This gives me the following output from 'security dump-trust-settings':

$ security dump-trust-settings
Number of trusted certs = 1
Cert 0: clockwork.apple.com
   Number of trust settings : 3
   Trust Setting 0:
      Policy OID            : SSL
      Policy String         : clockwork.apple.com
      Allowed Error         : Host name mismatch
      Result Type           : kSecTrustSettingsResultTrustAsRoot
   Trust Setting 1:
      Policy OID            : Apple X509 Basic
      Result Type           : kSecTrustSettingsResultTrustAsRoot
   Trust Setting 2:
      Allowed Error         : CSSMERR_TP_CERT_EXPIRED
      Result Type           : kSecTrustSettingsResultTrustAsRoot

Notice that the certificate is allowed to have a hostname mismatch error, but ONLY if we're going to "clockwork.apple.com" using SSL. It is also marked as trusted for the X.509 Basic policy, and it is allowed to be expired. Also note that this certificate is NOT self- signed, so the result type here is kSecTrustSettingsResultTrustAsRoot rather than kSecTrustSettingsResultTrustRoot (which you'd expect to see if the certificate were self-signed.) "Trust as root" means that we don't need to build the chain further back to an actual root in order to consider this certificate trusted.

Also note that, by default, this command shows the trust settings for the user's trust domain. You can pass the -d option to the command and get the list of what's trusted in the admin trust domain (typically, this will include any root certificates which you've trusted manually.) Passing -s instead of -d shows the system trust domain, which includes all the Apple-provided root certificates.

-ken


_______________________________________________ Do not post admin requests to the list. They will be ignored. Apple-cdsa mailing list (email@hidden) Help/Unsubscribe/Update your Subscription: This email sent to email@hidden
References: 
 >Trouble getting trust settings to stick (From: Rich Siegel <email@hidden>)



Visit the Apple Store online or at retail locations.
1-800-MY-APPLE

Contact Apple | Terms of Use | Privacy Policy

Copyright © 2011 Apple Inc. All rights reserved.