在 iPhone/Cocoa 上复制 OpenSSL smime 命令

Posted

技术标签:

【中文标题】在 iPhone/Cocoa 上复制 OpenSSL smime 命令【英文标题】:Replicate OpenSSL smime command on iPhone/Cocoa 【发布时间】:2012-06-16 05:18:40 【问题描述】:

我试图做的是复制以下命令通过 Mac 上的终端运行,但在 iPhone/in Cocoa 上:

openssl smime -binary -sign -signer cert.pem -inkey key.pem -in file.txt -out encrypted -outform DER

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

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

在关注this cocoa sn-p 使用.p12 证书加密文件后,我不确定这是否是正确的方法。

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

【问题讨论】:

不知道答案,但祝您的 PassKit 应用程序好运! 【参考方案1】:

据我所知 - 你有点过分了 - 桨被锁在了应用商店中。

ios 缺少您需要的 CMSEncoderAddSigners、CMSEncoderUpdateContent、CMSEncoderCopyEncodedContent。 使用 openssl 或 Chilkat 也不理想 - 因为 iOS 的钥匙串 API 不允许您在导入后(不再)访问私钥。

我过去用 openssl 和 Chilkat 解决了这个问题。

然而,在每种情况下,我都会“缓存”私钥的副本——一旦它进入钥匙串——我能得到的只是一个 SecKeyRef(你需要与苹果签订额外的协议/许可才能能够将其取出并仍在应用商店中。对任何 ***(例如瞻博网络)应用程序进行逆向工程以查看要链接的方法/框架。

对于 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;

警告:在上面我已经剥离了大多数 mngt/错误管理和/或将其替换为断言,否则它会变得有点过于使用。

谢谢,

Dw.

【讨论】:

以上是关于在 iPhone/Cocoa 上复制 OpenSSL smime 命令的主要内容,如果未能解决你的问题,请参考以下文章

加密技术---openss 理论

Linux里面openss-devel是啥?

iPhone 原生应用的测试驱动设计

F5运维之 将Windows中的证书导入F5

Centos 7.4中的远程访问控制

MySQL JDBC over SSL 问题