2012-04-13 112 views
1

我發現了使用APNS和可可的真棒解釋。 APNS Pusher 現在我不想每次選擇我的SecIdentityRef(因爲我很懶)我試着把SecIdentityRef放到NSData中並保存到默認值。下一次應用程序啓動時,我再次加載它,它總是得到exc_bad_access。這裏是我添加的代碼:將SecIdentityRef存儲到NSUserDefaults

// For saving 
NSData *secRefData = [NSData dataWithBytes:[SFChooseIdentityPanel sharedChooseIdentityPanel].identity length:sizeof([SFChooseIdentityPanel sharedChooseIdentityPanel].identity)]; 
[[NSUserDefaults standardUserDefaults] setValue:secRefData forKey:@"identity"]; 

//For loading 
NSData *secRefData = [[NSUserDefaults standardUserDefaults] valueForKey:@"identity"]; 
if([secRefData length] != 0) { 
    [[APNS sharedAPNS] setIdentity:(SecIdentityRef)CFRetain([secRefData bytes])]; 
} 

我如何得到這個工作?有另外一種方法可以存儲身份嗎?

編輯

所以我發現保存標識的名稱,並開始它看起來應用程序可用的身份擁有這個名字,並使用一個具有正確的名稱時的解決方案。這裏的代碼:

//For loading 
    NSString *lastIdentityName = [[NSUserDefaults standardUserDefaults] valueForKey:@"identityName"]; 
    if([lastIdentityName length] != 0) { 
     NSArray *allIdentities = [self identities]; 
     for (id object in allIdentities) { 
      NSString *theName = [[[X509Certificate extractCertDictFromIdentity:(SecIdentityRef)object] valueForKey:@"Subject"] objectForKey:@"CommonName"]; 
      if([theName isEqualToString:lastIdentityName]) { 
       [[APNS sharedAPNS] setIdentity:(SecIdentityRef)CFRetain((__bridge_retained SecIdentityRef)object)]; 
       [[NSUserDefaults standardUserDefaults] setValue:[self identityName] forKey:@"identityName"]; 
       // KVO trigger 
       [self willChangeValueForKey:@"identityName"]; 
       [self didChangeValueForKey:@"identityName"]; 
      } 
     } 
    } 

//For saving 
    [[NSUserDefaults standardUserDefaults] setValue:[self identityName] forKey:@"identityName"]; 

回答

0

這一切都搞砸了。 A SecIdentityRef是對內部對象的不透明引用。你把它看作是指向那個對象的指針,但它可能只是一個表格或其他東西的索引。

其次,你不知道內部對象的大小。您的sizeof表達式產生指針的大小,而不是它所指向的對象。沒有辦法獲得實際大小,因爲該類型是不透明的。

最後,沒有理由相信對象是寫入文件然後讀出並保持完整的「標量」數據。很可能,對象包含內部指針,這在別的進程的地址空間中是沒有意義的。更何況你沒有保存和恢復這些指針可能指向的任何事實。

+0

非常感謝。但我如何正確存儲選定的身份? – thomasguenzel 2012-04-13 12:09:53

+0

我不確定。我看到'SecIdentityCopyCertificate()'和'SecCertificateCopyData()',然後在另一個方向'SecCertificateCreateWithData()'和'SecIdentityCreateWithCertificate()'。但是,我對這些東西並不十分熟悉,我不確定是否會通過將證書數據保存爲用戶默認值來破壞安全性。 'SecIdentityCopyCertificate()'的文檔也表示可以將輸出轉換爲'SecKeychainItemRef'並且我看到'SecKeychainItemCreatePersistentReference()',這看起來很有前途。然後,反過來,'SecKeychainItemCopyFromPersistentReference()'。 – 2012-04-13 12:40:16

1

使用SecKeychainItemCreatePersistentReference()SecKeychainItemCopyFromPersistentReference() - 它們可以在進程之間傳遞或持久化。有一些注意事項,但:

  1. 你不能堅持一個身份,只有一個證書,所以你必須經過額外的啤酒花之間進行轉換。
  2. 你會得到NSData與長和不透明的數據塊,所以你必須存儲它,而不是例如。作爲一個字符串;並忘記能夠手動編輯此設置。

這就是我在我的PDF簽名應用程序中這樣做的,到目前爲止它的工作原理完美無瑕。以下是相關部分的代碼:

- (NSData*) identityToPersistent:(SecIdentityRef)ident 
{ 
    OSStatus status; 
    SecCertificateRef cert; 
    CFDataRef data = nil; 

    status = SecIdentityCopyCertificate(ident, &cert); 
    if (status != noErr) 
     return nil; 
    status = SecKeychainItemCreatePersistentReference((SecKeychainItemRef)cert, &data); 
    CFRelease(cert); 
    if (status != noErr) 
     return nil; 

    return CFBridgingRelease(data); 
} 

- (SecIdentityRef) identityFromPersistent:(NSData*)data 
{ 
    OSStatus status; 
    SecKeychainItemRef cert; 
    SecIdentityRef ident = nil; 

    status = SecKeychainItemCopyFromPersistentReference((__bridge CFDataRef)data, &cert); 
    if (status != noErr) 
     return nil; 
    status = SecIdentityCreateWithCertificate(NULL, (SecCertificateRef)cert, &ident); 
    CFRelease(cert); 

    return ident; 
} 


- (SecIdentityRef) getPreferredIdentity 
{ 
    NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:@"SigningIdentity"]; 
    if (!data) 
     return nil; 
    return [self identityFromPersistent:data]; 
} 

- (void) setPreferredIdentity:(SecIdentityRef)ident 
{ 
    NSData *data = [self identityToPersistent:ident]; 
    [[NSUserDefaults standardUserDefaults] setObject:data forKey:@"SigningIdentity"]; 
} 
相關問題