如何在 iOS 安全传输 API 中使用我自己的根证书?
How to use my own root certificate in iOS Secure Transport API?
我正在尝试在已建立的传输层之上使用 Apple's Secure Transport API,并使用我自己的根证书。我的根证书是 SecCertificateRef
,但我不知道如何让它可信。
我检查了以下函数,每个函数似乎都非常接近我需要的:
SSLAddDistinguishedName()
未实现;
SSLSetTrustedRoots()
已弃用;
SSLSetCertificateAuthorities()
仅用于客户端身份验证。
如果我可以覆盖 SecContextRef
中的 SecTrustRef
,那么 SecTrustSetAnchorCertificates()
就可以完成这项工作。不幸的是,这条路只把我带到了 SSLGetPeerSecTrust()
,这似乎是 Apple-private API。
如果我理解这一点,你正在尝试:
{您的应用} --[ssl 会话]--> {您的服务器}
您的服务器正在使用一些由您自己的 CA (root) 签名的证书。您正在尝试将您的 CA 证书与 phone 一起发送,并将其用作受信任的 CA,而不是现有的全球 CA。
这似乎是您要查找的内容:
Preparing for a session
Call SSLNewContext (in OS X) or SSLCreateContext (in iOS and OS X) to
create a new SSL session context.
Write the SSLWrite andSSLRead I/O functions and call SSLSetIOFuncs to
pass them to Secure Transport.
Establish a connection using CFNetwork, BSD Sockets, or Open
Transport. Then call SSLSetConnection to specify the connection to
which the SSL session context applies.
Call SSLSetPeerDomainName to specify the fully-qualified domain name
of the peer to which you want to connect (optional but highly
recommended).
Call SSLSetCertificate to specify the certificate to be used in
authentication (required for server side, optional for client).
OSStatus SSLSetCertificate ( SSLContextRef context, CFArrayRef certRefs );
certRefs
要设置的证书。此数组包含 SecCertificateRef 类型的项,但 certRefs[0] 除外,它的类型为 SecIdentityRef.
Discussion Setting the certificate or certificates is mandatory for
server connections, but is optional for clients. Specifying a
certificate for a client enables SSL client-side authentication. You
must place in certRefs[0] a SecIdentityRef object that identifies the
leaf certificate and its corresponding private key. Specifying a root
certificate is optional; if it’s not specified, the root certificate
that verifies the certificate chain specified here must be present in
the system wide set of trusted anchor certificates.
来自:https://developer.apple.com/library/mac/documentation/Security/Reference/secureTransportRef/
我想你想要的是:
OSStatus status = SSLSetSessionOption(sslContext, kSSLSessionOptionBreakOnServerAuth, true);
然后在握手期间
OSStatus status = SSLHandshake(sslContext);
if (status == errSSLPeerAuthCompleted)
{
SecTrustRef trust = NULL;
status = SSLCopyPeerTrust(sslContext, &trust);
// Perform your custom trust rules here. e.g.
BOOL bTrusted = NO;
NSArray* anchor = [NSArray arrayWithObject:(id)pCACert];
OSStatus result = SecTrustSetAnchorCertificates(trust, (CFArrayRef)anchor);
/* Uncomment this to enable both system certs and the one we are supplying */
//result = SecTrustSetAnchorCertificatesOnly(trust, NO);
SecTrustResultType trustResult;
result = SecTrustEvaluate(trust, &trustResult);
if (result == errSecSuccess)
{
switch (trustResult)
{
case kSecTrustResultProceed:
case kSecTrustResultUnspecified:
bTrusted = YES;
break;
case kSecTrustResultInvalid:
case kSecTrustResultDeny:
case kSecTrustResultRecoverableTrustFailure:
case kSecTrustResultFatalTrustFailure:
case kSecTrustResultOtherError:
default:
break;
}
}
// If trusted, continue the handshake
if (bTrusted)
status = SSLHandshake(sslContext);
else
{
/* Your trust failure handling here ~ disconnect */
}
}
其中 pCAcert 是您希望信任的根证书 (SecCertificateRef)
我正在尝试在已建立的传输层之上使用 Apple's Secure Transport API,并使用我自己的根证书。我的根证书是 SecCertificateRef
,但我不知道如何让它可信。
我检查了以下函数,每个函数似乎都非常接近我需要的:
SSLAddDistinguishedName()
未实现;SSLSetTrustedRoots()
已弃用;SSLSetCertificateAuthorities()
仅用于客户端身份验证。
如果我可以覆盖 SecContextRef
中的 SecTrustRef
,那么 SecTrustSetAnchorCertificates()
就可以完成这项工作。不幸的是,这条路只把我带到了 SSLGetPeerSecTrust()
,这似乎是 Apple-private API。
如果我理解这一点,你正在尝试:
{您的应用} --[ssl 会话]--> {您的服务器}
您的服务器正在使用一些由您自己的 CA (root) 签名的证书。您正在尝试将您的 CA 证书与 phone 一起发送,并将其用作受信任的 CA,而不是现有的全球 CA。
这似乎是您要查找的内容:
Preparing for a session
Call SSLNewContext (in OS X) or SSLCreateContext (in iOS and OS X) to create a new SSL session context.
Write the SSLWrite andSSLRead I/O functions and call SSLSetIOFuncs to pass them to Secure Transport.
Establish a connection using CFNetwork, BSD Sockets, or Open Transport. Then call SSLSetConnection to specify the connection to which the SSL session context applies.
Call SSLSetPeerDomainName to specify the fully-qualified domain name of the peer to which you want to connect (optional but highly recommended).
Call SSLSetCertificate to specify the certificate to be used in authentication (required for server side, optional for client).
OSStatus SSLSetCertificate ( SSLContextRef context, CFArrayRef certRefs );
certRefs
要设置的证书。此数组包含 SecCertificateRef 类型的项,但 certRefs[0] 除外,它的类型为 SecIdentityRef.
Discussion Setting the certificate or certificates is mandatory for server connections, but is optional for clients. Specifying a certificate for a client enables SSL client-side authentication. You must place in certRefs[0] a SecIdentityRef object that identifies the leaf certificate and its corresponding private key. Specifying a root certificate is optional; if it’s not specified, the root certificate that verifies the certificate chain specified here must be present in the system wide set of trusted anchor certificates.
来自:https://developer.apple.com/library/mac/documentation/Security/Reference/secureTransportRef/
我想你想要的是:
OSStatus status = SSLSetSessionOption(sslContext, kSSLSessionOptionBreakOnServerAuth, true);
然后在握手期间
OSStatus status = SSLHandshake(sslContext);
if (status == errSSLPeerAuthCompleted)
{
SecTrustRef trust = NULL;
status = SSLCopyPeerTrust(sslContext, &trust);
// Perform your custom trust rules here. e.g.
BOOL bTrusted = NO;
NSArray* anchor = [NSArray arrayWithObject:(id)pCACert];
OSStatus result = SecTrustSetAnchorCertificates(trust, (CFArrayRef)anchor);
/* Uncomment this to enable both system certs and the one we are supplying */
//result = SecTrustSetAnchorCertificatesOnly(trust, NO);
SecTrustResultType trustResult;
result = SecTrustEvaluate(trust, &trustResult);
if (result == errSecSuccess)
{
switch (trustResult)
{
case kSecTrustResultProceed:
case kSecTrustResultUnspecified:
bTrusted = YES;
break;
case kSecTrustResultInvalid:
case kSecTrustResultDeny:
case kSecTrustResultRecoverableTrustFailure:
case kSecTrustResultFatalTrustFailure:
case kSecTrustResultOtherError:
default:
break;
}
}
// If trusted, continue the handshake
if (bTrusted)
status = SSLHandshake(sslContext);
else
{
/* Your trust failure handling here ~ disconnect */
}
}
其中 pCAcert 是您希望信任的根证书 (SecCertificateRef)