Pregunta

I have imported a self-signed X509 certificate into my iPhone by simply emailing the certificate.pem to it and installing it on the device. Now I would like to verify a particular certificate in my iOS application that must be signed using the aforementioned certificate. Basically, the imported certificate acts as root certificate for a CA.

Does the imported certificate get stored in the Keychain?

How can I programmatically validate another certificate based on the imported one? (the second certificate is only valid if it is signed by the before imported CA certificate)

Does anyone have some experienced with these scenarios?

Thanks in advance!

¿Fue útil?

Solución

1) yes - it sits in your keychain.

2) you verify it using the trust SecTrustCreateWithCertificates(), SecTrustEvaluate() against either all certificates or just your own.

3) If you verified it against a wide smattering of certs you can optionally lookup your own cert in the keychain; get the DER; calculate its SHA1 and compare this to a SHA1 which is hardcoded in your code.

The code is something like below.

NSMutableArray *serverChain = -- array with what you want to check
NSMutableArray *trustedCertRefs = <your-hardcoded-certs>;

SecTrustRef noHostTrustRef = NULL;
OSErr status = SecTrustCreateWithCertificates((__bridge CFArrayRef)serverChain,
                                 SecPolicyCreateSSL(NO, nil), &noHostTrustRef);

if (status != noErr) {
    NSLog(@"SecTrustCreateWithCertificates failed: %hd", status);
    [[challenge sender] cancelAuthenticationChallenge:challenge];
}


status = SecTrustSetAnchorCertificates(noHostTrustRef,
                         (__bridge CFArrayRef)trustedCertRefs);
if (status != noErr) {
    NSLog(@"SecTrustSetAnchorCertificates failed: %hd", status);
    [[challenge sender] cancelAuthenticationChallenge:challenge];
}

status = SecTrustEvaluate(noHostTrustRef, &result);
if (status != noErr) {
    NSLog(@"SecTrustEvaluate failed: %hd", status);
    [[challenge sender] cancelAuthenticationChallenge:challenge];
}
CFRelease(noHostTrustRef);

/* From SecTrust.h:
 *
 * SecTrustResultType results have two dimensions.  They specify both whether 
 * evaluation suceeded and whether this is because of a user decision.  
 *
 * In practice the commonly expected result is kSecTrustResultUnspecified,
 * which indicates a positive result that wasn't decided by the user.  
 *
 * The common failure is kSecTrustResultRecoverableTrustFailure, which means a
 * negative result.  kSecTrustResultProceed and kSecTrustResultDeny are the
 * positive and negative result respectively when decided by the user.  User
 *  decisions are persisted through the use of SecTrustCopyExceptions() and
 * SecTrustSetExceptions().  Finally kSecTrustResultFatalTrustFailure is a
 * negative result that should not be circumvented.  In fact only in the case
 * of kSecTrustResultRecoverableTrustFailure should a user ever be asked.
 */
switch (result) {
    case kSecTrustResultProceed: // 1
    case kSecTrustResultConfirm: // 2
    case kSecTrustResultUnspecified: // 4
        return YES
        break;
    case kSecTrustResultRecoverableTrustFailure:  // 5
    case kSecTrustResultDeny: // 3
    case kSecTrustResultFatalTrustFailure: // 6
    case kSecTrustResultOtherError: // 7
    case kSecTrustResultInvalid: // 0
    default:
        return NO:
        break;
}
[[challenge sender] cancelAuthenticationChallenge:challenge];

or if you get a trust chain, say from the network stack which is already verified against the keychain (and thus against your certs) - then you can extract the certs; do a SecCertificateCopyData() on them; and then SHA1 that NSData to compare to your hardcoded sha1 as to ensure it is verified against exactly that one.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top