Создание SecCertificateRef для задачи проверки подлинности NSURLConnection


Я получаю вызов аутентификации от сервера, к которому пытается подключиться мое приложение, поэтому я реализовал Метод connection:didReceiveAuthenticationChallenge:. Мне нужно отправить a SecCertificateRef и A SecIdentityRef. Удостоверение работает, но сертификат должен быть отправлен как NSArray, и я не могу понять, как преобразовать CFArrayRef в NSArray.

Это мой метод для создания удостоверения и сертификата:

// Returns an array containing the certificate
- (CFArrayRef)getCertificate {
  SecCertificateRef certificate = nil;
  NSString *thePath = [[NSBundle mainBundle] pathForResource:@"CertificateName" ofType:@"p12"];
  NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
  CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
  certificate = SecCertificateCreateWithData(nil, inPKCS12Data);
  SecCertificateRef certs[1] = { certificate };
  CFArrayRef array = CFArrayCreate(NULL, (const void **) certs, 1, NULL);

  SecPolicyRef myPolicy   = SecPolicyCreateBasicX509();
  SecTrustRef myTrust;

  OSStatus status = SecTrustCreateWithCertificates(array, myPolicy, &myTrust);
  if (status == noErr) {
    NSLog(@"No Err creating certificate");
  } else {
    NSLog(@"Possible Err Creating certificate");
  }
  return array;
}

// Returns the identity
- (SecIdentityRef)getClientCertificate {
  SecIdentityRef identityApp = nil;
  NSString *thePath = [[NSBundle mainBundle] pathForResource:@"CertificateName" ofType:@"p12"];
  NSData *PKCS12Data = [[NSData alloc] initWithContentsOfFile:thePath];
  CFDataRef inPKCS12Data = (__bridge CFDataRef)PKCS12Data;
  CFStringRef password = CFSTR("password");
  const void *keys[] = { kSecImportExportPassphrase };//kSecImportExportPassphrase };
  const void *values[] = { password };
  CFDictionaryRef options = CFDictionaryCreate(NULL, keys, values, 1, NULL, NULL);
  CFArrayRef items = CFArrayCreate(NULL, 0, 0, NULL);
  OSStatus securityError = SecPKCS12Import(inPKCS12Data, options, &items);
  CFRelease(options);
  CFRelease(password);
  if (securityError == errSecSuccess) {
    NSLog(@"Success opening p12 certificate. Items: %ld", CFArrayGetCount(items));
    CFDictionaryRef identityDict = CFArrayGetValueAtIndex(items, 0);
    identityApp = (SecIdentityRef)CFDictionaryGetValue(identityDict, kSecImportItemIdentity);
  } else {
    NSLog(@"Error opening Certificate.");
  }
  return identityApp;
}

А затем в connection:didReceiveAuthenticationChallenge: у меня есть:

- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {
  if ([challenge previousFailureCount] == 0) {
    SecIdentityRef identity = [self getClientCertificate];  // Go get a SecIdentityRef
    CFArrayRef certs = [self getCertificate]; // Get an array of certificates

    // Convert the CFArrayRef to a NSArray
    NSArray *myArray = (__bridge NSArray *)certs;

    // Create the NSURLCredential
    NSURLCredential *newCredential = [NSURLCredential credentialWithIdentity:identity certificates:certs persistence:NSURLCredentialPersistenceNone];

    // Send
    [challenge.sender useCredential:newCredential forAuthenticationChallenge:challenge];
  } else {
    // Failed
    [[challenge sender] cancelAuthenticationChallenge:challenge];
  }
}

Приложение аварийно завершает работу, когда NSURLCredential созданный. При дальнейшем рассмотрении я пришел к выводу, что при преобразовании CFArrayRef в NSArray данные SecCertificateRef теряются, и массив содержит null, вызывающий сбой.

Как я могу поместить SecCertificateRef в NSArray? Я пропустил шаг или просто делаю это неправильно?

1 6

1 ответ:

Наконец-то я нашел ответ. Я должен был использовать SecIdentityCopyCertificate(identity, &certificateRef); вместо SecCertificateCreateWithData(nil, inPKCS12Data); для создания моего сертификата.