summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/base/x509_cert_types.cc48
-rw-r--r--net/base/x509_cert_types.h22
-rw-r--r--net/base/x509_certificate.h2
-rw-r--r--net/base/x509_certificate_mac.cc116
-rw-r--r--net/base/x509_openssl_util.cc53
5 files changed, 125 insertions, 116 deletions
diff --git a/net/base/x509_cert_types.cc b/net/base/x509_cert_types.cc
index cdfbdaa..6beb3ec 100644
--- a/net/base/x509_cert_types.cc
+++ b/net/base/x509_cert_types.cc
@@ -6,9 +6,27 @@
#include "net/base/x509_certificate.h"
#include "base/logging.h"
+#include "base/string_number_conversions.h"
+#include "base/string_piece.h"
+#include "base/time.h"
namespace net {
+namespace {
+
+// Helper for ParseCertificateDate. |*field| must contain at least
+// |field_len| characters. |*field| will be advanced by |field_len| on exit.
+// |*ok| is set to false if there is an error in parsing the number, but left
+// untouched otherwise. Returns the parsed integer.
+int ParseIntAndAdvance(const char** field, size_t field_len, bool* ok) {
+ int result = 0;
+ *ok &= base::StringToInt(*field, *field + field_len, &result);
+ *field += field_len;
+ return result;
+}
+
+} // namespace
+
CertPrincipal::CertPrincipal() {
}
@@ -75,4 +93,34 @@ bool CertPolicy::HasDeniedCert() const {
return !denied_.empty();
}
+bool ParseCertificateDate(const base::StringPiece& raw_date,
+ CertDateFormat format,
+ base::Time* time) {
+ size_t year_length = format == CERT_DATE_FORMAT_UTC_TIME ? 2 : 4;
+
+ if (raw_date.length() < 11 + year_length)
+ return false;
+
+ const char* field = raw_date.data();
+ bool valid = true;
+ base::Time::Exploded exploded = {0};
+
+ exploded.year = ParseIntAndAdvance(&field, year_length, &valid);
+ exploded.month = ParseIntAndAdvance(&field, 2, &valid);
+ exploded.day_of_month = ParseIntAndAdvance(&field, 2, &valid);
+ exploded.hour = ParseIntAndAdvance(&field, 2, &valid);
+ exploded.minute = ParseIntAndAdvance(&field, 2, &valid);
+ exploded.second = ParseIntAndAdvance(&field, 2, &valid);
+ if (valid && year_length == 2)
+ exploded.year += exploded.year < 50 ? 2000 : 1900;
+
+ valid &= exploded.HasValidValues();
+
+ if (!valid)
+ return false;
+
+ *time = base::Time::FromUTCExploded(exploded);
+ return true;
+}
+
} // namespace net
diff --git a/net/base/x509_cert_types.h b/net/base/x509_cert_types.h
index f762e56..eb3ad60 100644
--- a/net/base/x509_cert_types.h
+++ b/net/base/x509_cert_types.h
@@ -18,6 +18,11 @@
#include <Security/x509defs.h>
#endif
+namespace base {
+class Time;
+class StringPiece;
+} // namespace base
+
namespace net {
class X509Certificate;
@@ -127,6 +132,23 @@ inline bool CSSMOIDEqual(const CSSM_OID* oid1, const CSSM_OID* oid2) {
}
#endif
+// A list of ASN.1 date/time formats that ParseCertificateDate() supports,
+// encoded in the canonical forms specified in RFC 2459/3280/5280.
+enum CertDateFormat {
+ // UTCTime: Format is YYMMDDHHMMSSZ
+ CERT_DATE_FORMAT_UTC_TIME,
+
+ // GeneralizedTime: Format is YYYYMMDDHHMMSSZ
+ CERT_DATE_FORMAT_GENERALIZED_TIME,
+};
+
+// Attempts to parse |raw_date|, an ASN.1 date/time string encoded as
+// |format|, and writes the result into |*time|. If an invalid date is
+// specified, or if parsing fails, returns false, and |*time| will not be
+// updated.
+bool ParseCertificateDate(const base::StringPiece& raw_date,
+ CertDateFormat format,
+ base::Time* time);
} // namespace net
#endif // NET_BASE_X509_CERT_TYPES_H_
diff --git a/net/base/x509_certificate.h b/net/base/x509_certificate.h
index c0342a1..c2a378a 100644
--- a/net/base/x509_certificate.h
+++ b/net/base/x509_certificate.h
@@ -220,7 +220,7 @@ class X509Certificate : public base::RefCountedThreadSafe<X509Certificate> {
static bool GetSSLClientCertificates(
const std::string& server_domain,
const std::vector<CertPrincipal>& valid_issuers,
- std::vector<scoped_refptr<X509Certificate> >* certs);
+ CertificateList* certs);
// Creates the chain of certs to use for this client identity cert.
CFArrayRef CreateClientCertificateChain() const;
diff --git a/net/base/x509_certificate_mac.cc b/net/base/x509_certificate_mac.cc
index 5a5d457c..d4858e6 100644
--- a/net/base/x509_certificate_mac.cc
+++ b/net/base/x509_certificate_mac.cc
@@ -222,9 +222,10 @@ void GetCertGeneralNamesForOID(X509Certificate::OSCertHandle cert_handle,
for (size_t field = 0; field < fields.num_of_fields; ++field) {
if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) {
CSSM_X509_EXTENSION_PTR cssm_ext =
- (CSSM_X509_EXTENSION_PTR)fields.fields[field].FieldValue.Data;
+ reinterpret_cast<CSSM_X509_EXTENSION_PTR>(
+ fields.fields[field].FieldValue.Data);
CE_GeneralNames* alt_name =
- (CE_GeneralNames*) cssm_ext->value.parsedValue;
+ reinterpret_cast<CE_GeneralNames*>(cssm_ext->value.parsedValue);
for (size_t name = 0; name < alt_name->numNames; ++name) {
const CE_GeneralName& name_struct = alt_name->generalName[name];
@@ -235,10 +236,9 @@ void GetCertGeneralNamesForOID(X509Certificate::OSCertHandle cert_handle,
// CE_GeneralNameType for more information.
if (name_struct.nameType == name_type) {
const CSSM_DATA& name_data = name_struct.name;
- std::string value =
- std::string(reinterpret_cast<std::string::value_type*>
- (name_data.Data),
- name_data.Length);
+ std::string value = std::string(
+ reinterpret_cast<const char*>(name_data.Data),
+ name_data.Length);
result->push_back(value);
}
}
@@ -257,43 +257,23 @@ void GetCertDateForOID(X509Certificate::OSCertHandle cert_handle,
for (size_t field = 0; field < fields.num_of_fields; ++field) {
if (CSSMOIDEqual(&fields.fields[field].FieldOid, &oid)) {
- CSSM_X509_TIME* x509_time =
- reinterpret_cast<CSSM_X509_TIME *>
- (fields.fields[field].FieldValue.Data);
- std::string time_string =
- std::string(reinterpret_cast<std::string::value_type*>
- (x509_time->time.Data),
- x509_time->time.Length);
-
- DCHECK(x509_time->timeType == BER_TAG_UTC_TIME ||
- x509_time->timeType == BER_TAG_GENERALIZED_TIME);
-
- struct tm time;
- const char* parse_string;
- if (x509_time->timeType == BER_TAG_UTC_TIME)
- parse_string = "%y%m%d%H%M%SZ";
- else if (x509_time->timeType == BER_TAG_GENERALIZED_TIME)
- parse_string = "%y%m%d%H%M%SZ";
- else {
- // Those are the only two BER tags for time; if neither are used then
- // this is a rather broken cert.
+ CSSM_X509_TIME* x509_time = reinterpret_cast<CSSM_X509_TIME*>(
+ fields.fields[field].FieldValue.Data);
+ if (x509_time->timeType != BER_TAG_UTC_TIME &&
+ x509_time->timeType != BER_TAG_GENERALIZED_TIME) {
+ LOG(ERROR) << "Unsupported date/time format "
+ << x509_time->timeType;
return;
}
- strptime(time_string.c_str(), parse_string, &time);
-
- Time::Exploded exploded;
- exploded.year = time.tm_year + 1900;
- exploded.month = time.tm_mon + 1;
- exploded.day_of_week = time.tm_wday;
- exploded.day_of_month = time.tm_mday;
- exploded.hour = time.tm_hour;
- exploded.minute = time.tm_min;
- exploded.second = time.tm_sec;
- exploded.millisecond = 0;
-
- *result = Time::FromUTCExploded(exploded);
- break;
+ base::StringPiece time_string(
+ reinterpret_cast<const char*>(x509_time->time.Data),
+ x509_time->time.Length);
+ CertDateFormat format = x509_time->timeType == BER_TAG_UTC_TIME ?
+ CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME;
+ if (!ParseCertificateDate(time_string, format, result))
+ LOG(ERROR) << "Invalid certificate date/time " << time_string;
+ return;
}
}
}
@@ -334,7 +314,8 @@ OSStatus CreatePolicy(const CSSM_OID* policy_OID,
// 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);
+ DCHECK(cert_handle);
+ DCHECK(out_cert_chain);
// Create an SSL policy ref configured for client cert evaluation.
SecPolicyRef ssl_policy;
OSStatus result = X509Certificate::CreateSSLClientPolicy(&ssl_policy);
@@ -343,9 +324,9 @@ OSStatus CopyCertChain(SecCertificateRef cert_handle,
ScopedCFTypeRef<SecPolicyRef> scoped_ssl_policy(ssl_policy);
// Create a SecTrustRef.
- ScopedCFTypeRef<CFArrayRef> input_certs(
- CFArrayCreate(NULL, (const void**)&cert_handle, 1,
- &kCFTypeArrayCallBacks));
+ ScopedCFTypeRef<CFArrayRef> input_certs(CFArrayCreate(
+ NULL, const_cast<const void**>(reinterpret_cast<void**>(&cert_handle)),
+ 1, &kCFTypeArrayCallBacks));
SecTrustRef trust_ref = NULL;
result = SecTrustCreateWithCertificates(input_certs, ssl_policy, &trust_ref);
if (result)
@@ -400,8 +381,8 @@ void AddCertificatesFromBytes(const char* data, size_t length,
X509Certificate::OSCertHandles* output) {
SecExternalFormat input_format = format;
ScopedCFTypeRef<CFDataRef> local_data(CFDataCreateWithBytesNoCopy(
- kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data),
- length, kCFAllocatorNull));
+ kCFAllocatorDefault, reinterpret_cast<const UInt8*>(data), length,
+ kCFAllocatorNull));
CFArrayRef items = NULL;
OSStatus status = SecKeychainItemImport(local_data, NULL, &input_format,
@@ -452,13 +433,12 @@ void SetMacTestCertificate(X509Certificate* cert) {
void X509Certificate::Initialize() {
const CSSM_X509_NAME* name;
OSStatus status = SecCertificateGetSubject(cert_handle_, &name);
- if (!status) {
+ if (!status)
subject_.Parse(name);
- }
+
status = SecCertificateGetIssuer(cert_handle_, &name);
- if (!status) {
+ if (!status)
issuer_.Parse(name);
- }
GetCertDateForOID(cert_handle_, CSSMOID_X509V1ValidityNotBefore,
&valid_start_);
@@ -659,9 +639,8 @@ int X509Certificate::Verify(const std::string& hostname, int flags,
if (cert_status == CERT_STATUS_COMMON_NAME_INVALID) {
std::vector<std::string> names;
GetDNSNames(&names);
- if (OverrideHostnameMismatch(hostname, &names)) {
+ if (OverrideHostnameMismatch(hostname, &names))
cert_status = 0;
- }
}
verify_result->cert_status |= cert_status;
}
@@ -682,9 +661,8 @@ int X509Certificate::Verify(const std::string& hostname, int flags,
if (status)
return NetErrorFromOSStatus(status);
verify_result->cert_status |= CertStatusFromOSStatus(cssm_result);
- if (!verify_result->cert_status) {
+ if (!verify_result->cert_status)
verify_result->cert_status |= CERT_STATUS_INVALID;
- }
break;
}
@@ -818,8 +796,8 @@ SHA1Fingerprint X509Certificate::CalculateFingerprint(
if (status)
return sha1;
- DCHECK(NULL != cert_data.Data);
- DCHECK(0 != cert_data.Length);
+ DCHECK(cert_data.Data);
+ DCHECK_NE(cert_data.Length, 0U);
CC_SHA1(cert_data.Data, cert_data.Length, sha1.data);
@@ -870,7 +848,7 @@ bool X509Certificate::IsIssuedBy(
CFArrayRef cert_chain = NULL;
OSStatus result;
result = CopyCertChain(os_cert_handle(), &cert_chain);
- if (result != noErr)
+ if (result)
return false;
ScopedCFTypeRef<CFArrayRef> scoped_cert_chain(cert_chain);
@@ -906,20 +884,22 @@ OSStatus X509Certificate::CreateSSLClientPolicy(SecPolicyRef* out_policy) {
}
// static
-bool X509Certificate::GetSSLClientCertificates (
+bool X509Certificate::GetSSLClientCertificates(
const std::string& server_domain,
const std::vector<CertPrincipal>& valid_issuers,
- std::vector<scoped_refptr<X509Certificate> >* certs) {
+ CertificateList* certs) {
ScopedCFTypeRef<SecIdentityRef> preferred_identity;
if (!server_domain.empty()) {
// See if there's an identity preference for this domain:
ScopedCFTypeRef<CFStringRef> domain_str(
base::SysUTF8ToCFStringRef("https://" + server_domain));
SecIdentityRef identity = NULL;
- if (SecIdentityCopyPreference(domain_str,
- 0,
- NULL, // validIssuers argument is ignored :(
- &identity) == noErr)
+ // While SecIdentityCopyPreferences appears to take a list of CA issuers
+ // to restrict the identity search to, within Security.framework the
+ // argument is ignored and filtering unimplemented. See
+ // SecIdentity.cpp in libsecurity_keychain, specifically
+ // _SecIdentityCopyPreferenceMatchingName().
+ if (SecIdentityCopyPreference(domain_str, 0, NULL, &identity) == noErr)
preferred_identity.reset(identity);
}
@@ -997,8 +977,10 @@ CFArrayRef X509Certificate::CreateClientCertificateChain() const {
CFArrayRef cert_chain = NULL;
result = CopyCertChain(cert_handle_, &cert_chain);
- if (result)
- goto exit;
+ if (result) {
+ LOG(ERROR) << "CreateIdentityCertificateChain error " << result;
+ return chain.release();
+ }
// Append the intermediate certs from SecTrust to the result array:
if (cert_chain) {
@@ -1010,9 +992,7 @@ CFArrayRef X509Certificate::CreateClientCertificateChain() const {
}
CFRelease(cert_chain);
}
-exit:
- if (result)
- LOG(ERROR) << "CreateIdentityCertificateChain error " << result;
+
return chain.release();
}
diff --git a/net/base/x509_openssl_util.cc b/net/base/x509_openssl_util.cc
index 0bb4002..81424cc 100644
--- a/net/base/x509_openssl_util.cc
+++ b/net/base/x509_openssl_util.cc
@@ -5,30 +5,14 @@
#include "net/base/x509_openssl_util.h"
#include "base/logging.h"
-#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_util.h"
-#include "base/time.h"
+#include "net/base/x509_cert_types.h"
namespace net {
namespace x509_openssl_util {
-namespace {
-
-// Helper for ParseDate. |*field| must contain at least |field_len| characters.
-// |*field| will be advanced by |field_len| on exit. |*ok| is set to false if
-// there is an error in parsing the number, but left untouched otherwise.
-// Returns the parsed integer.
-int ParseIntAndAdvance(const char** field, size_t field_len, bool* ok) {
- int result = 0;
- *ok &= base::StringToInt(*field, *field + field_len, &result);
- *field += field_len;
- return result;
-}
-
-} // namespace
-
bool ParsePrincipalKeyAndValueByIndex(X509_NAME* name,
int index,
std::string* key,
@@ -78,35 +62,10 @@ bool ParseDate(ASN1_TIME* x509_time, base::Time* time) {
base::StringPiece str_date(reinterpret_cast<const char*>(x509_time->data),
x509_time->length);
- // UTCTime: YYMMDDHHMMSSZ
- // GeneralizedTime: YYYYMMDDHHMMSSZ
- size_t year_length = x509_time->type == V_ASN1_UTCTIME ? 2 : 4;
-
- if (str_date.length() < 11 + year_length)
- return false;
-
- const char* field = str_date.data();
- bool valid = true;
- base::Time::Exploded exploded = {0};
- exploded.year = ParseIntAndAdvance(&field, year_length, &valid);
- exploded.month = ParseIntAndAdvance(&field, 2, &valid);
- exploded.day_of_month = ParseIntAndAdvance(&field, 2, &valid);
- exploded.hour = ParseIntAndAdvance(&field, 2, &valid);
- exploded.minute = ParseIntAndAdvance(&field, 2, &valid);
- exploded.second = ParseIntAndAdvance(&field, 2, &valid);
- if (valid && year_length == 2)
- exploded.year += exploded.year < 50 ? 2000 : 1900;
-
- valid &= exploded.HasValidValues();
-
- if (!valid) {
- NOTREACHED() << "can't parse x509 date " << str_date;
- return false;
- }
-
- *time = base::Time::FromUTCExploded(exploded);
- return true;
+ CertDateFormat format = x509_time->type == V_ASN1_UTCTIME ?
+ CERT_DATE_FORMAT_UTC_TIME : CERT_DATE_FORMAT_GENERALIZED_TIME;
+ return ParseCertificateDate(str_date, format, time);
}
// TODO(joth): Investigate if we can upstream this into the OpenSSL library,
@@ -225,6 +184,6 @@ bool VerifyHostname(const std::string& hostname,
return false;
}
-} // namespace x509_openssl_util
+} // namespace x509_openssl_util
-} // namespace net
+} // namespace net