无法以编程方式在iOS上安装.der证书

时间:2016-09-29 17:20:54

标签: ios objective-c ssl encryption

我试图以编程方式在iOS(iPhone / iPhone模拟器)上安装SSL证书。 我已使用this small guide成功创建并安装了.crt但是当我尝试将获得的server.crt转换为server.der并以编程方式安装时,我得到{ {1}}。请注意,我在iOS上使用此CFNetwork SSLHandshake failed (-9807)版本的此版本,在OS X openssl服务器上使用.der版本。

转换:

.crt

在OS X上接收:

openssl x509 -outform der -in server.crt -out server.der

在iOS上安装和发送:

openssl s_server -key server.key -cert server.crt -accept 1678

那么,如何在iOS上正确转换和安装 NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSData *iosTrustedCertDerData = [NSData dataWithContentsOfFile:[bundle pathForResource:@"certificate" ofType:@"der"]]; OSStatus err = noErr; SecCertificateRef cert; cert = SecCertificateCreateWithData(NULL, (CFDataRef) iosTrustedCertDerData); assert(cert != NULL); CFTypeRef result; NSDictionary* dict = [NSDictionary dictionaryWithObjectsAndKeys: (id)kSecClassCertificate, kSecClass, cert, kSecValueRef, nil]; err = SecItemAdd((CFDictionaryRef)dict, &result); assert(err == noErr || err == errSecDuplicateItem); printf("adding finished \n"); if ((err == noErr) || (err == errSecDuplicateItem)) { printf("success \n"); CFReadStreamRef readStream; CFWriteStreamRef writeStream; CFStreamCreatePairWithSocketToHost(NULL, (CFStringRef)@"localhost", 1678, &readStream, &writeStream); CFReadStreamSetProperty(readStream, kCFStreamPropertySocketSecurityLevel, kCFStreamSocketSecurityLevelTLSv1); CFReadStreamOpen(readStream); CFWriteStreamOpen(writeStream); UInt8 buf[] = "Hello from iOS\n"; int bytesWritten = CFWriteStreamWrite(writeStream, buf, strlen((char*)buf)); } 证书?

UPD:

.der

此行发生异常:

 NSBundle *bundle = [NSBundle bundleForClass:[self class]];

    NSString *resourcePath = [bundle pathForResource:@"certificate" ofType:@"der"];

    NSData *certData = [NSData dataWithContentsOfFile:resourcePath];

    NSString* publickKeyRef = @"certificate_der";

    NSData* headerStrippedData = [self stripPublicKeyHeader:certData];
    [self addPeerPublicKey:publickKeyRef keyBits:headerStrippedData];

    SecKeyRef ref= [self getPublicKeyReference:publickKeyRef];

    printf("adding finished \n");


    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;
    CFStreamCreatePairWithSocketToHost(NULL,
                                       (CFStringRef)@"localhost",
                                       1678,
                                       &readStream,
                                       &writeStream);
    CFReadStreamSetProperty(readStream,
                            kCFStreamPropertySocketSecurityLevel,
                            kCFStreamSocketSecurityLevelTLSv1);
    CFReadStreamOpen(readStream);
    CFWriteStreamOpen(writeStream);

例外:

[self addPeerPublicKey:publickKeyRef keyBits:headerStrippedData];

1 个答案:

答案 0 :(得分:2)

在iOS中,它有点不同,您需要将此.der文件添加到钥匙串中,然后从钥匙链中将其引回。我给出了以下代码来添加并从钥匙串中取回

- (void)addPeerPublicKey:(NSString *)peerName keyBits:(NSData *)publicKeyData {

    OSStatus sanityCheck = noErr;
    CFTypeRef persistPeer = NULL;
    [self removePeerPublicKey:peerName];

    NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]];
    NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init];
    [peerPublicKeyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass];
    [peerPublicKeyAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [peerPublicKeyAttr setObject:peerTag forKey:(id)kSecAttrApplicationTag];
    [peerPublicKeyAttr setObject:publicKeyData forKey:(id)kSecValueData];
    [peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:(id)kSecReturnData];
    sanityCheck = SecItemAdd((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef *)&persistPeer);

    if(sanityCheck == errSecDuplicateItem)
    {
        NSLog(@"HanselErrorCode: -1");
    }

    persistPeer = NULL;
    [peerPublicKeyAttr removeObjectForKey:(id)kSecValueData];
    sanityCheck = SecItemCopyMatching((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef*)&persistPeer);

    if (persistPeer) CFRelease(persistPeer);
}

-(SecKeyRef)getPublicKeyReference:(NSString*)peerName
{
    OSStatus sanityCheck = noErr;

    SecKeyRef pubKeyRefData = NULL;
    NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]];
    NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init];

    [peerPublicKeyAttr setObject:(id)kSecClassKey forKey:(id)kSecClass];
    [peerPublicKeyAttr setObject:(id)kSecAttrKeyTypeRSA forKey:(id)kSecAttrKeyType];
    [peerPublicKeyAttr setObject:peerTag forKey:(id)kSecAttrApplicationTag];
    [peerPublicKeyAttr setObject:[NSNumber numberWithBool:YES] forKey:       (id)kSecReturnRef];
    sanityCheck = SecItemCopyMatching((CFDictionaryRef) peerPublicKeyAttr, (CFTypeRef*)&pubKeyRefData);

    if(pubKeyRefData)
    {
        return pubKeyRefData;
    }
    else
    {
        return nil;
    }
}

- (NSData *)stripPublicKeyHeader:(NSData *)d_key
{
    // Skip ASN.1 public key header
    if (d_key == nil) return(nil);

    unsigned int len = (unsigned int)[d_key length];
    if (!len) return(nil);

    unsigned char *c_key = (unsigned char *)[d_key bytes];
    unsigned int  idx    = 0;

    if (c_key[idx++] != 0x30) return(nil);

    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
    else idx++;

    // PKCS #1 rsaEncryption szOID_RSA_RSA
    static unsigned char seqiod[] =
    { 0x30,   0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01,
        0x01, 0x05, 0x00 };
    if (memcmp(&c_key[idx], seqiod, 15)) return(nil);

    idx += 15;

    if (c_key[idx++] != 0x03) return(nil);

    if (c_key[idx] > 0x80) idx += c_key[idx] - 0x80 + 1;
    else idx++;

    if (c_key[idx++] != '\0') return(nil);

    // Now make a new NSData from this buffer
    return([NSData dataWithBytes:&c_key[idx] length:len - idx]);

}


- (void)removePeerPublicKey:(NSString *)peerName
{
    OSStatus sanityCheck = noErr;

    NSData * peerTag = [[NSData alloc] initWithBytes:(const void *)[peerName UTF8String] length:[peerName length]];
    NSMutableDictionary * peerPublicKeyAttr = [[NSMutableDictionary alloc] init];

    [peerPublicKeyAttr setObject:(__bridge id)kSecClassKey forKey:(__bridge id)kSecClass];
    [peerPublicKeyAttr setObject:(__bridge id)kSecAttrKeyTypeRSA forKey:(__bridge id)kSecAttrKeyType];
    [peerPublicKeyAttr setObject:peerTag forKey:(__bridge id)kSecAttrApplicationTag];

    sanityCheck = SecItemDelete((__bridge CFDictionaryRef) peerPublicKeyAttr);
}

要使用此密钥,您必须执行以下操作

NSString *resourcePath = [bundle pathForResource:@"publickey" ofType:@"der"];
    NSData *certData = [NSData dataWithContentsOfFile:resourcePath];

    NSData* headerStrippedData = [self stripPublicKeyHeader:certData];
    [self addPeerPublicKey:publickKeyRef keyBits:headerStrippedData];

    SecKeyRef ref= [self getPublicKeyReference:publickKeyRef];

并最终使用ref用于所有目的。

NSString* publickKeyRef = @"key_name_against_which_you_want_to_save_your_der";

此代码显示了添加它,恢复并使用它的方法。几个月前我从互联网上获取了这个代码 - 如果找到的话,添加源代码链接。在Xcode8中,您必须添加密钥链的名称(publickKeyRef),您将在功能部分中使用此文件。