summaryrefslogtreecommitdiffstats
path: root/net/base/x509_certificate_mac.cc
diff options
context:
space:
mode:
Diffstat (limited to 'net/base/x509_certificate_mac.cc')
-rw-r--r--net/base/x509_certificate_mac.cc198
1 files changed, 92 insertions, 106 deletions
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc
index 16e7604..a4c37ba 100644
--- a/net/base/x509_certificate_mac.cc
+++ b/net/base/x509_certificate_mac.cc
@@ -5,6 +5,7 @@
#include "net/base/x509_certificate.h"
#include <CommonCrypto/CommonDigest.h>
+#include <Security/Security.h>
#include <time.h>
#include "base/scoped_cftyperef.h"
@@ -80,11 +81,6 @@ namespace {
typedef OSStatus (*SecTrustCopyExtendedResultFuncPtr)(SecTrustRef,
CFDictionaryRef*);
-inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) {
- return oid1->Length == oid2->Length &&
- (memcmp(oid1->Data, oid2->Data, oid1->Length) == 0);
-}
-
int NetErrorFromOSStatus(OSStatus status) {
switch (status) {
case noErr:
@@ -173,64 +169,6 @@ bool OverrideHostnameMismatch(const std::string& hostname,
return override_hostname_mismatch;
}
-void ParsePrincipal(const CSSM_X509_NAME* name,
- X509Certificate::Principal* principal) {
- std::vector<std::string> common_names, locality_names, state_names,
- country_names;
-
- // TODO(jcampan): add business_category and serial_number.
- const CSSM_OID* kOIDs[] = { &CSSMOID_CommonName,
- &CSSMOID_LocalityName,
- &CSSMOID_StateProvinceName,
- &CSSMOID_CountryName,
- &CSSMOID_StreetAddress,
- &CSSMOID_OrganizationName,
- &CSSMOID_OrganizationalUnitName,
- &CSSMOID_DNQualifier }; // This should be "DC"
- // but is undoubtedly
- // wrong. TODO(avi):
- // Find the right OID.
-
- std::vector<std::string>* values[] = {
- &common_names, &locality_names,
- &state_names, &country_names,
- &(principal->street_addresses),
- &(principal->organization_names),
- &(principal->organization_unit_names),
- &(principal->domain_components) };
- DCHECK(arraysize(kOIDs) == arraysize(values));
-
- for (size_t rdn = 0; rdn < name->numberOfRDNs; ++rdn) {
- CSSM_X509_RDN rdn_struct = name->RelativeDistinguishedName[rdn];
- for (size_t pair = 0; pair < rdn_struct.numberOfPairs; ++pair) {
- CSSM_X509_TYPE_VALUE_PAIR pair_struct =
- rdn_struct.AttributeTypeAndValue[pair];
- for (size_t oid = 0; oid < arraysize(kOIDs); ++oid) {
- if (CSSMOIDEqual(&pair_struct.type, kOIDs[oid])) {
- std::string value =
- std::string(reinterpret_cast<std::string::value_type*>
- (pair_struct.value.Data),
- pair_struct.value.Length);
- values[oid]->push_back(value);
- break;
- }
- }
- }
- }
-
- // We don't expect to have more than one CN, L, S, and C.
- std::vector<std::string>* single_value_lists[4] = {
- &common_names, &locality_names, &state_names, &country_names };
- std::string* single_values[4] = {
- &principal->common_name, &principal->locality_name,
- &principal->state_or_province_name, &principal->country_name };
- for (size_t i = 0; i < arraysize(single_value_lists); ++i) {
- DCHECK(single_value_lists[i]->size() <= 1);
- if (single_value_lists[i]->size() > 0)
- *(single_values[i]) = (*(single_value_lists[i]))[0];
- }
-}
-
struct CSSMFields {
CSSMFields() : cl_handle(NULL), num_of_fields(0), fields(NULL) {}
~CSSMFields() {
@@ -386,17 +324,51 @@ OSStatus CreatePolicy(const CSSM_OID* policy_OID,
return noErr;
}
+// Gets the issuer for a given cert, starting with the cert itself and
+// including the intermediate and finally root certificates (if any).
+// This function calls SecTrust but doesn't actually pay attention to the trust
+// result: it shouldn't be used to determine trust, just to traverse the chain.
+// Caller is responsible for releasing the value stored into *out_cert_chain.
+OSStatus CopyCertChain(SecCertificateRef cert_handle,
+ CFArrayRef* out_cert_chain) {
+ DCHECK(cert_handle && out_cert_chain);
+ // Create an SSL policy ref configured for client cert evaluation.
+ SecPolicyRef ssl_policy;
+ OSStatus result = X509Certificate::CreateSSLClientPolicy(&ssl_policy);
+ if (result)
+ return result;
+ scoped_cftyperef<SecPolicyRef> scoped_ssl_policy(ssl_policy);
+
+ // Create a SecTrustRef.
+ scoped_cftyperef<CFArrayRef> input_certs(
+ CFArrayCreate(NULL, (const void**)&cert_handle, 1,
+ &kCFTypeArrayCallBacks));
+ SecTrustRef trust_ref = NULL;
+ result = SecTrustCreateWithCertificates(input_certs, ssl_policy, &trust_ref);
+ if (result)
+ return result;
+ scoped_cftyperef<SecTrustRef> trust(trust_ref);
+
+ // Evaluate trust, which creates the cert chain.
+ SecTrustResultType status;
+ CSSM_TP_APPLE_EVIDENCE_INFO* status_chain;
+ result = SecTrustEvaluate(trust, &status);
+ if (result)
+ return result;
+ return SecTrustGetResult(trust, &status, out_cert_chain, &status_chain);
+}
+
} // namespace
void X509Certificate::Initialize() {
const CSSM_X509_NAME* name;
OSStatus status = SecCertificateGetSubject(cert_handle_, &name);
if (!status) {
- ParsePrincipal(name, &subject_);
+ subject_.Parse(name);
}
status = SecCertificateGetIssuer(cert_handle_, &name);
if (!status) {
- ParsePrincipal(name, &issuer_);
+ issuer_.Parse(name);
}
GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore,
@@ -742,6 +714,34 @@ bool X509Certificate::SupportsSSLClientAuth() const {
return false;
}
+bool X509Certificate::IsIssuedBy(
+ const std::vector<CertPrincipal>& valid_issuers) {
+ // Get the cert's issuer chain.
+ CFArrayRef cert_chain = NULL;
+ OSStatus result;
+ result = CopyCertChain(os_cert_handle(), &cert_chain);
+ if (result != noErr)
+ return false;
+ scoped_cftyperef<CFArrayRef> scoped_cert_chain(cert_chain);
+
+ // Check all the certs in the chain for a match.
+ int n = CFArrayGetCount(cert_chain);
+ for (int i = 0; i < n; ++i) {
+ SecCertificateRef cert_handle = reinterpret_cast<SecCertificateRef>(
+ const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i)));
+ CFRetain(cert_handle);
+ scoped_refptr<X509Certificate> cert = X509Certificate::CreateFromHandle(
+ cert_handle,
+ X509Certificate::SOURCE_LONE_CERT_IMPORT,
+ X509Certificate::OSCertHandles());
+ for (unsigned j = 0; j < valid_issuers.size(); j++) {
+ if (cert->subject().Matches(valid_issuers[j]))
+ return true;
+ }
+ }
+ return false;
+}
+
// static
OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) {
CSSM_APPLE_TP_SSL_OPTIONS tp_ssl_options = {
@@ -759,6 +759,7 @@ OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) {
// static
bool X509Certificate::GetSSLClientCertificates (
const std::string& server_domain,
+ const std::vector<Principal>& valid_issuers,
std::vector<scoped_refptr<X509Certificate> >* certs) {
scoped_cftyperef<SecIdentityRef> preferred_identity;
if (!server_domain.empty()) {
@@ -768,11 +769,12 @@ bool X509Certificate::GetSSLClientCertificates (
SecIdentityRef identity = NULL;
if (SecIdentityCopyPreference(domain_str,
0,
- NULL,
+ NULL, // validIssuers argument is ignored :(
&identity) == noErr)
preferred_identity.reset(identity);
}
+ // Now enumerate the identities in the available keychains.
SecIdentitySearchRef search = nil;
OSStatus err = SecIdentitySearchCreate(NULL, CSSM_KEYUSE_SIGN, &search);
scoped_cftyperef<SecIdentitySearchRef> scoped_search(search);
@@ -805,10 +807,20 @@ bool X509Certificate::GetSSLClientCertificates (
if (i < certs->size())
continue;
+ bool is_preferred = preferred_identity &&
+ CFEqual(preferred_identity, identity);
+
+ // Make sure the issuer matches valid_issuers, if given.
+ // But an explicit cert preference overrides this.
+ if (!is_preferred &&
+ valid_issuers.size() > 0 &&
+ !cert->IsIssuedBy(valid_issuers))
+ continue;
+
// The cert passes, so add it to the vector.
// If it's the preferred identity, add it at the start (so it'll be
// selected by default in the UI.)
- if (preferred_identity && CFEqual(preferred_identity, identity))
+ if (is_preferred)
certs->insert(certs->begin(), cert);
else
certs->push_back(cert);
@@ -834,46 +846,20 @@ CFArrayRef X509Certificate::CreateClientCertificateChain() const {
CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks));
CFArrayAppendValue(chain, identity);
- {
- // Create an SSL policy ref configured for client cert evaluation.
- SecPolicyRef ssl_policy;
- result = CreateSSLClientPolicy(&ssl_policy);
- if (result)
- goto exit;
- scoped_cftyperef<SecPolicyRef> scoped_ssl_policy(ssl_policy);
-
- // Use a SecTrust object to find the intermediate certs in the trust chain.
- scoped_cftyperef<CFArrayRef> input_certs(
- CFArrayCreate(NULL, (const void**)&cert_handle_, 1,
- &kCFTypeArrayCallBacks));
- SecTrustRef trust_ref = NULL;
- result = SecTrustCreateWithCertificates(input_certs,
- ssl_policy,
- &trust_ref);
- if (result)
- goto exit;
- scoped_cftyperef<SecTrustRef> trust(trust_ref);
-
- SecTrustResultType status;
- CFArrayRef trust_chain = NULL;
- CSSM_TP_APPLE_EVIDENCE_INFO* status_chain;
- result = SecTrustEvaluate(trust, &status);
- if (result)
- goto exit;
- result = SecTrustGetResult(trust, &status, &trust_chain, &status_chain);
- if (result)
- goto exit;
-
- // Append the intermediate certs from SecTrust to the result array:
- if (trust_chain) {
- int chain_count = CFArrayGetCount(trust_chain);
- if (chain_count > 1) {
- CFArrayAppendArray(chain,
- trust_chain,
- CFRangeMake(1, chain_count - 1));
- }
- CFRelease(trust_chain);
+ CFArrayRef cert_chain = NULL;
+ result = CopyCertChain(cert_handle_, &cert_chain);
+ if (result)
+ goto exit;
+
+ // Append the intermediate certs from SecTrust to the result array:
+ if (cert_chain) {
+ int chain_count = CFArrayGetCount(cert_chain);
+ if (chain_count > 1) {
+ CFArrayAppendArray(chain,
+ cert_chain,
+ CFRangeMake(1, chain_count - 1));
}
+ CFRelease(cert_chain);
}
exit:
if (result)