我试图以编程方式在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];
答案 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
),您将在功能部分中使用此文件。