在iPhone/Cocoa上复制OpenSSL smime命令

7
我正在尝试在iPhone / Cocoa上复制以下命令在Mac终端中运行的操作:
openssl smime -binary -sign -signer cert.pem -inkey key.pem -in file.txt -out encrypted -outform DER

其中“encrypted”是由该命令生成的加密文件。

尽管它指定了两个独立的密钥(公钥和私钥),但可以将它们作为单个.p12文件。

按照 Cocoas代码片段加密一个文件使用.p12证书后,我不确定这是否是正确的方法。

在iPhone上复制smime命令的最佳途径是什么(如上面的终端命令),或者通过可用的Security.framework/CommonCrypto方法根本不可能吗?


不知道答案,但祝你的PassKit应用好运! - Paul Wagener
1个回答

3
据我所知,你在应用商店中遇到了困境,需要使用的CMSEncoderAddSigners、CMSEncoderUpdateContent和CMSEncoderCopyEncodedContent等功能在iOS中均不可用。同时,使用openssl或Chilkat也不是理想的选择,因为iOS的密钥链API一旦导入私钥之后就无法再次访问私钥。
我以前曾经用过openssl和Chilkat来解决这个问题。 然而,在每种情况下,我都会“缓存”私钥的副本,因为一旦它进入密钥链中,我只能获得一个SecKeyRef(您需要与苹果达成额外的协议/权限才能将其取回并仍然在应用商店中)。 反向工程任何VPN(例如Juniper)应用程序以查看链接方法/框架。
对于openssl,只需采用openssl应用程序中的smime.c代码进行修改即可。 对于Chilkat,则要简单得多。
    CkoCert * mine = [identity ckoCert];

    assert([mime AddEncryptCert: mine] == YES);

    for(id cc in backupCerts) {
        assert([mime AddEncryptCert:cc] == YES);
    }

    for(id key in [headers allKeys]) {
        [mime SetHeaderField:[NSString stringWithFormat:@"%s%@", X_HDR_PREFIX, key]
                       value:[headers objectForKey:key]
         ];
    };

    [mime SetBodyFromBinary:data];        
    assert([mime EncryptN] == YES);

    return  [mime GetMimeBytes];

并且当身份字段具有“保留自己的缓存”作弊时:

-(id)initWithPKCS12:(NSData*)pkcs12der password:(NSString *)password {
    if (password == nil)
        password = [APPSETTINGS wellKnownPkcsPassword];

    NSDictionary *options = [NSDictionary dictionaryWithObjectsAndKeys:
                             password, kSecImportExportPassphrase,
                             nil];

    CFArrayRef items;
    OSStatus status = SecPKCS12Import((__bridge CFDataRef)pkcs12der,  
        (__bridge CFDictionaryRef)options, &items);

    if (status != noErr) {
        NSLog(@"PKCS12 importAsDer failed: Error %ld",(long)status);
        ...
    }

    if (!items || CFArrayGetCount(items) < 1) {
        NSLog(@"PKCS12 importAsDer failed - nothing returned (%ld bytes DER)", 
              (long)[pkcs12der length]);
        ...
    }

    CFDictionaryRef dict0 = (CFDictionaryRef) CFArrayGetValueAtIndex(items, 0);
    if (!dict0)
        return nil;

    SecIdentityRef iRef = (SecIdentityRef) CFDictionaryGetValue(dict0, 
            kSecImportItemIdentity);
    CFArrayRef cRef = (CFArrayRef) CFDictionaryGetValue(dict0, kSecImportItemCertChain);

    self = [self initWithIdentityRef:iRef withChainArrayRef:cRef];
    CFRelease(items);

#if TARGET_OS_IPHONE
    // We lack SecPrivate* on iOS. So we cheat a bit - rather than
    // use the keychain we limt ourselves to our own *.p12's and
    // keep a copy of the private key in memory.
    //
#  ifdef WITH_OPENSSL

   const unsigned char * ptr = [pkcs12der bytes];
    PKCS12 * p12 = d2i_PKCS12(NULL, &ptr, len);
    char buff[1024];

    if (!p12) {
       NSLog(@"Could not decode PKCS#12: %s", ERR_error_string(ERR_get_error(), buff));
       ...
    };

    const char * pass = [password cStringUsingEncoding:NSASCIIStringEncoding];

   if (PKCS12_parse(p12, pass, &pkey, &x509, NULL) != 1) {
      NSLog(@"Could not parse PKCS#12: %s", ERR_error_string(ERR_get_error(), buff));
      ...
    };
    ....
#  else
    ckoCert = [[CkoCert alloc] init];

    if (!([ckoCert LoadPfxData:pkcs12der password:[APPSETTINGS wellKnownPkcsPassword]])) {
        NSLog(@"PKCS12 loadPfxData failed: %@", [ckoCert LastErrorText]);
        ...
    }

    ckoPrivateKey = [ckoCert ExportPrivateKey];
#  endif // chilkat or openssl
#endif // iOS

    return self;
}

警告:上面我已经剥离了大部分的管理/错误管理,并将其替换为断言,否则它会变得太过复杂。

谢谢,

Dw.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接