Wie kann unter iOS eine Verbindung zu einem Server über https mit selbstsigniertem Zertifikat auf dem Server hergestellt werden?

Ich entwickle für iOS 5 und möchte eigentlich keine nicht-ARCed-Codes verwenden. Deshalb habe ich mich dafür entschieden, dies selbst zu implementieren, anstatt AFNetworking zu verwenden. Auch dies könnte eine große Frage sein, also habe ich sie in zwei kleinere Teile geteilt.

1) Herstellen einer Verbindung zum Server unter Verwendung von https in iOS 5. Ich verwende hier die Codes aus "iOS 5 Programming Pushing the Limits". Da ich für iOS 5 entwickle, verwende ich in meinem Projekt nicht die veralteten Methoden. "RNSecTrustEvaluateAsX509" ist eine Methode, die das Zertifikat als einfaches X.509-Zertifikat und nicht als Teil eines SSL-Handshakes neu bewertet.

- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{

    NSURLProtectionSpace *protSpace =  challenge.protectionSpace;
    SecTrustRef trust = protSpace.serverTrust;
    SecTrustResultType result = kSecTrustResultFatalTrustFailure;

    OSStatus status = SecTrustEvaluate(trust, &result);

    if (status == errSecSuccess && result == kSecTrustResultRecoverableTrustFailure) {
        SecCertificateRef cert = SecTrustGetCertificateAtIndex(trust, 0);
        CFStringRef subject = SecCertificateCopySubjectSummary(cert);

        NSLog(@"Trying to access %@. Got %@.", protSpace.host,
              (__bridge id)subject);
        CFRange range = CFStringFind(subject, CFSTR("192.168.1.100"), kCFCompareAnchored|kCFCompareBackwards);
        if (range.location != kCFNotFound) {
            NSLog(@"Creating new trust certificate.Ignoring the hostname.");
            status = RNSecTrustEvaluateAsX509(trust, &result);
        }
        CFRelease(subject);
    }

    if (status == errSecSuccess) {
        switch (result) {
            case kSecTrustResultInvalid:
            case kSecTrustResultDeny:
            case kSecTrustResultFatalTrustFailure:
            case kSecTrustResultOtherError:
            case kSecTrustResultRecoverableTrustFailure: {
                NSLog(@"Failing due to result: %lu", result);
                [challenge.sender cancelAuthenticationChallenge:challenge];
            }

                break;
            case kSecTrustResultProceed:
            case kSecTrustResultUnspecified: {
                NSLog(@"Successing with result: %lu", result);
                NSURLCredential *cred = [NSURLCredential credentialForTrust:trust];
                [challenge.sender useCredential:cred forAuthenticationChallenge:challenge];
            }
                break;
            default:
                NSAssert(NO,@"Unexpected result from trust evaluation: %d", result);
                break;
        }
    }
    else {
        // Something was broken
        NSLog(@"Complete failure with code: %lu", status);
        [challenge.sender cancelAuthenticationChallenge:challenge];
    }

}

Es wird eine Verbindung zum Server hergestellt, aber es wird immer die Fehlermeldung "Der Vorgang konnte nicht abgeschlossen werden (NSURLErrorDomain-Fehler -1012)" angezeigt. Und die Konsole zeigt "Fehler aufgrund von Ergebnis 5" an, was bedeutet, dass ich ein kSecTrustResultRecoverableTrustFailure erhalte. Ich vermute, dass dies darauf zurückzuführen ist, dass ich ein selbstsigniertes Zertifikat auf dem Server verwende. Dies führt zu dem folgenden zweiten Problem.

2) Selbstsigniertes Zertifikat verursacht Probleme. Also habe ich diese Zeilen hinzugefügt

// Self-signed certificates need to be validated manually.
NSArray *anchors = [self serverAnchors];

SecTrustSetAnchorCertificates(trust, (__bridge CFArrayRef)anchors);
SecTrustSetAnchorCertificatesOnly(trust, YES);

kurz bevor

OSStatus status = SecTrustEvaluate(trust, &result);

in der obigen Methode willSendRequestForAuthenticationChallenge. und ich habe auch eine Methode erstellt:

- (NSArray *)serverAnchors
{
    static NSArray *anchors = nil;
    if (!anchors) {
        NSData *caData = [CA_CERTS dataUsingEncoding:NSUTF8StringEncoding];
        SecCertificateRef caRef = SecCertificateCreateWithData(kCFAllocatorDefault, (__bridge CFDataRef) caData);

        anchors = [NSArray arrayWithObjects:(__bridge id)caRef,  nil];

        if (caRef) {
            CFRelease(caRef);   
        }
    }

    return anchors;
}

Ich habe CA_CERTS als die Zertifikatdaten im "der" -Format definiert. Dies ist eine NSS-Zeichenfolge, die ich über SecCertificateCopyData vom Server erhalten habe. Aber ich bekomme immer noch kSecTrustResultRecoverableTrustFailure. Ich weiß nicht wirklich, ob ich hier das Richtige tue. Wie kann ich das selbstsignierte Zertifikat vom Server mithilfe seiner eigenen Daten manuell validieren? Genauer gesagt, wie bekommt man seine Daten von iOS?

Antworten auf die Frage(1)

Ihre Antwort auf die Frage