2011-04-24 16 views

Respuesta

13

Después de la minería de la documentación, archivos de cabecera y los archivos de origen, se me ha ocurrido con el siguiente código:

#import <Security/Security.h> 

- (void)logMessageForStatus:(OSStatus)status 
       functionName:(NSString *)functionName 
{ 
    CFStringRef errorMessage; 
    errorMessage = SecCopyErrorMessageString(status, NULL); 
    NSLog(@"error after %@: %@", functionName, (NSString *)errorMessage); 
    CFRelease(errorMessage); 
} 

- (void)listCertificates 
{ 
    OSStatus status; 
    SecKeychainSearchRef search = NULL; 

    // The first argument being NULL indicates the user's current keychain list 
    status = SecKeychainSearchCreateFromAttributes(NULL, 
     kSecCertificateItemClass, NULL, &search); 

    if (status != errSecSuccess) { 
     [self logMessageForStatus:status 
        functionName:@"SecKeychainSearchCreateFromAttributes()"]; 
     return; 
    } 

    SecKeychainItemRef searchItem = NULL; 

    while (SecKeychainSearchCopyNext(search, &searchItem) != errSecItemNotFound) { 
     SecKeychainAttributeList attrList; 
     CSSM_DATA certData; 

     attrList.count = 0; 
     attrList.attr = NULL; 

     status = SecKeychainItemCopyContent(searchItem, NULL, &attrList, 
      (UInt32 *)(&certData.Length), 
      (void **)(&certData.Data)); 

     if (status != errSecSuccess) { 
      [self logMessageForStatus:status 
         functionName:@"SecKeychainItemCopyContent()"]; 
      CFRelease(searchItem); 
      continue; 
     } 

     // At this point you should have a valid CSSM_DATA structure 
     // representing the certificate 

     SecCertificateRef certificate; 
     status = SecCertificateCreateFromData(&certData, CSSM_CERT_X_509v3, 
      CSSM_CERT_ENCODING_BER, &certificate); 

     if (status != errSecSuccess) { 
      [self logMessageForStatus:status 
         functionName:@"SecCertificateCreateFromData()"]; 
      SecKeychainItemFreeContent(&attrList, certData.Data); 
      CFRelease(searchItem); 
      continue; 
     } 

     // Do whatever you want to do with the certificate 
     // For instance, print its common name (if there's one) 

     CFStringRef commonName = NULL; 
     SecCertificateCopyCommonName(certificate, &commonName); 
     NSLog(@"common name = %@", (NSString *)commonName); 
     if (commonName) CFRelease(commonName); 

     SecKeychainItemFreeContent(&attrList, certData.Data); 
     CFRelease(searchItem); 
    } 

    CFRelease(search); 
} 
+1

Absolutamente brillante. Muchas gracias! –

+0

@Dylan Cheers. Considere archivar un radar de solicitud de mejora (o tres, en realidad) con Apple: este podría ser un código de muestra, esto podría estar en la Guía de programación de seguridad, y podrían proporcionar una API más simple basada en Cocoa para esto. –

+1

El 'searchItem' devuelto por' SecKeychainSearchCopyNext' ya es un 'SecCertificateRef'. (Está buscando elementos en la clase de certificado, por lo que cada resultado es un elemento de certificado.) No es necesario extraer y reinterpretar sus datos: un simple encasillado obtendrá mejores resultados. –

13

Si se dirige a Mac OS 10.6 o posterior, puede utilizar SecItemCopyMatching para consultar fácilmente la llavero:

SecKeychainRef keychain = ... 
NSDictionary *query = [NSDictionary dictionaryWithObjectsAndKeys: 
         kSecClassCertificate, kSecClass, 
         [NSArray arrayWithObject:(id)keychain], kSecMatchSearchList, 
         kCFBooleanTrue, kSecReturnRef, 
         kSecMatchLimitAll, kSecMatchLimit, 
         nil]; 
NSArray *items = nil; 
OSStatus status = SecItemCopyMatching((CFDictionaryRef)query, (CFTypeRef *)&items); 
if (status) { 
    if (status != errSecItemNotFound) 
     LKKCReportError(status, @"Can't search keychain"); 
    return nil; 
} 
return [items autorelease]; // items contains all SecCertificateRefs in keychain 

Tenga en cuenta que no debe utilizar este para implementar la validación de certificados - la presencia de un certificado de CA en un llavero no indica que es de confianza para firmar certificados para cualquier política en particular. Consulte la Guía de programación de certificado, clave y confianza de para obtener información acerca de cómo realizar la validación de certificados con el llavero.

http://developer.apple.com/library/mac/#documentation/Security/Conceptual/CertKeyTrustProgGuide/03tasks/tasks.html#//apple_ref/doc/uid/TP40001358-CH205-SW1

+0

Esta es una gran respuesta, ya que 'SecKeychainSearchCreateFromAttributes' y' SecKeychainSearchCopyNext' están en desuso a partir de 10.7. Esto requiere algunas versiones locas para trabajar con ARC, pero usar un 'CFMutableDictionaryRef' y configurar estas teclas funciona igual de bien. ¡Gracias! –

Cuestiones relacionadas