Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "net/cert/cert_verify_proc_ios.h" | 5 #include "net/cert/cert_verify_proc_ios.h" |
| 6 | 6 |
| 7 #include <CommonCrypto/CommonDigest.h> | 7 #include <CommonCrypto/CommonDigest.h> |
| 8 #include <Security/Security.h> | 8 #include <Security/Security.h> |
| 9 | 9 |
| 10 #include "base/logging.h" | 10 #include "base/logging.h" |
| (...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 133 continue; | 133 continue; |
| 134 | 134 |
| 135 HashValue sha1(HASH_VALUE_SHA1); | 135 HashValue sha1(HASH_VALUE_SHA1); |
| 136 CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data()); | 136 CC_SHA1(spki_bytes.data(), spki_bytes.size(), sha1.data()); |
| 137 verify_result->public_key_hashes.push_back(sha1); | 137 verify_result->public_key_hashes.push_back(sha1); |
| 138 | 138 |
| 139 HashValue sha256(HASH_VALUE_SHA256); | 139 HashValue sha256(HASH_VALUE_SHA256); |
| 140 CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data()); | 140 CC_SHA256(spki_bytes.data(), spki_bytes.size(), sha256.data()); |
| 141 verify_result->public_key_hashes.push_back(sha256); | 141 verify_result->public_key_hashes.push_back(sha256); |
| 142 | 142 |
| 143 // Ignore the signature algorithm for the trust anchor. | |
| 144 if ((verify_result->cert_status & CERT_STATUS_AUTHORITY_INVALID) == 0 && | |
| 145 i == count - 1) { | |
| 146 continue; | |
| 147 } | |
| 148 | |
| 143 int sig_alg = OBJ_obj2nid(x509_cert->sig_alg->algorithm); | 149 int sig_alg = OBJ_obj2nid(x509_cert->sig_alg->algorithm); |
| 144 if (sig_alg == NID_md2WithRSAEncryption) { | 150 if (sig_alg == NID_md2WithRSAEncryption) { |
| 145 verify_result->has_md2 = true; | 151 verify_result->has_md2 = true; |
| 146 } else if (sig_alg == NID_md4WithRSAEncryption) { | 152 } else if (sig_alg == NID_md4WithRSAEncryption) { |
| 147 verify_result->has_md4 = true; | 153 verify_result->has_md4 = true; |
| 148 } else if (sig_alg == NID_md5WithRSAEncryption || | 154 } else if (sig_alg == NID_md5WithRSAEncryption || |
| 149 sig_alg == NID_md5WithRSA) { | 155 sig_alg == NID_md5WithRSA) { |
| 150 verify_result->has_md5 = true; | 156 verify_result->has_md5 = true; |
| 151 } else if (sig_alg == NID_sha1WithRSAEncryption || | 157 } else if (sig_alg == NID_sha1WithRSAEncryption || |
| 152 sig_alg == NID_dsaWithSHA || sig_alg == NID_dsaWithSHA1 || | 158 sig_alg == NID_dsaWithSHA || sig_alg == NID_dsaWithSHA1 || |
| 153 sig_alg == NID_dsaWithSHA1_2 || sig_alg == NID_sha1WithRSA || | 159 sig_alg == NID_dsaWithSHA1_2 || sig_alg == NID_sha1WithRSA || |
| 154 sig_alg == NID_ecdsa_with_SHA1) { | 160 sig_alg == NID_ecdsa_with_SHA1) { |
| 155 verify_result->has_sha1 = true; | 161 verify_result->has_sha1 = true; |
| 156 if (i == 0) | 162 if (i == 0) |
| 157 verify_result->has_sha1_leaf = true; | 163 verify_result->has_sha1_leaf = true; |
| 158 } | 164 } |
| 159 } | 165 } |
| 160 if (!verified_cert) { | 166 if (!verified_cert) { |
| 161 NOTREACHED(); | 167 NOTREACHED(); |
| 162 return; | 168 return; |
| 163 } | 169 } |
| 164 | 170 |
| 165 verify_result->verified_cert = | 171 verify_result->verified_cert = |
| 166 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | 172 X509Certificate::CreateFromHandle(verified_cert, verified_chain); |
| 167 } | 173 } |
| 168 | 174 |
| 175 // The iOS APIs don't expose an API-stable set of reasons for certificate | |
| 176 // validation failures. However, internally, the reason is tracked, and it's | |
| 177 // converted to user-facing localized strings. | |
| 178 // | |
| 179 // In the absence of a consistent API, convert the English strings to their | |
| 180 // localized counterpart, and then compare that with the error properties. If | |
|
Nico
2016/04/12 19:58:02
Hahahahaha
:-(
| |
| 181 // they're equal, it's a strong sign that this was the cause for the error. | |
| 182 // While this will break if/when iOS changes the contents of these strings, | |
| 183 // it's sufficient enough for now. | |
| 184 // | |
| 185 // TODO(rsleevi): https://crbug.com/601915 - Use a less brittle solution when | |
| 186 // possible. | |
| 187 CertStatus GetFailureFromTrustProperties(CFArrayRef properties) { | |
| 188 CertStatus reason = 0; | |
| 189 | |
| 190 if (!properties) | |
| 191 return CERT_STATUS_INVALID; | |
| 192 | |
| 193 const CFIndex properties_length = CFArrayGetCount(properties); | |
| 194 if (properties_length == 0) | |
| 195 return CERT_STATUS_INVALID; | |
| 196 | |
| 197 CFBundleRef bundle = | |
| 198 CFBundleGetBundleWithIdentifier(CFSTR("com.apple.Security")); | |
| 199 CFStringRef date_string = | |
| 200 CFSTR("One or more certificates have expired or are not valid yet."); | |
| 201 CFStringRef date_error = CFBundleCopyLocalizedString( | |
|
Eugene But (OOO till 7-30)
2016/04/14 17:49:12
This is a memory leak (and everything else returne
| |
| 202 bundle, date_string, date_string, CFSTR("SecCertificate")); | |
| 203 CFStringRef trust_string = CFSTR("Root certificate is not trusted."); | |
| 204 CFStringRef trust_error = CFBundleCopyLocalizedString( | |
| 205 bundle, trust_string, trust_string, CFSTR("SecCertificate")); | |
| 206 CFStringRef weak_string = | |
| 207 CFSTR("One or more certificates is using a weak key size."); | |
| 208 CFStringRef weak_error = CFBundleCopyLocalizedString( | |
| 209 bundle, weak_string, weak_string, CFSTR("SecCertificate")); | |
| 210 | |
| 211 for (CFIndex i = 0; i < properties_length; ++i) { | |
| 212 CFDictionaryRef dict = reinterpret_cast<CFDictionaryRef>( | |
| 213 const_cast<void*>(CFArrayGetValueAtIndex(properties, i))); | |
| 214 CFStringRef error = reinterpret_cast<CFStringRef>( | |
| 215 const_cast<void*>(CFDictionaryGetValue(dict, CFSTR("value")))); | |
| 216 | |
| 217 if (CFEqual(error, date_error)) { | |
| 218 reason |= CERT_STATUS_DATE_INVALID; | |
| 219 } else if (CFEqual(error, trust_error)) { | |
| 220 reason |= CERT_STATUS_AUTHORITY_INVALID; | |
| 221 } else if (CFEqual(error, weak_error)) { | |
| 222 reason |= CERT_STATUS_WEAK_KEY; | |
| 223 } else { | |
| 224 reason |= CERT_STATUS_INVALID; | |
| 225 } | |
| 226 } | |
| 227 | |
| 228 return reason; | |
| 229 } | |
| 230 | |
| 169 } // namespace | 231 } // namespace |
| 170 | 232 |
| 171 CertVerifyProcIOS::CertVerifyProcIOS() {} | 233 CertVerifyProcIOS::CertVerifyProcIOS() {} |
| 172 | 234 |
| 173 CertVerifyProcIOS::~CertVerifyProcIOS() {} | 235 CertVerifyProcIOS::~CertVerifyProcIOS() {} |
| 174 | 236 |
| 175 bool CertVerifyProcIOS::SupportsAdditionalTrustAnchors() const { | 237 bool CertVerifyProcIOS::SupportsAdditionalTrustAnchors() const { |
| 176 return false; | 238 return false; |
| 177 } | 239 } |
| 178 | 240 |
| (...skipping 21 matching lines...) Expand all Loading... | |
| 200 ScopedCFTypeRef<CFArrayRef> final_chain; | 262 ScopedCFTypeRef<CFArrayRef> final_chain; |
| 201 | 263 |
| 202 status = BuildAndEvaluateSecTrustRef(cert_array, trust_policies, &trust_ref, | 264 status = BuildAndEvaluateSecTrustRef(cert_array, trust_policies, &trust_ref, |
| 203 &final_chain, &trust_result); | 265 &final_chain, &trust_result); |
| 204 if (status) | 266 if (status) |
| 205 return NetErrorFromOSStatus(status); | 267 return NetErrorFromOSStatus(status); |
| 206 | 268 |
| 207 if (CFArrayGetCount(final_chain) == 0) | 269 if (CFArrayGetCount(final_chain) == 0) |
| 208 return ERR_FAILED; | 270 return ERR_FAILED; |
| 209 | 271 |
| 210 GetCertChainInfo(final_chain, verify_result); | |
| 211 | |
| 212 // TODO(sleevi): Support CRLSet revocation. | 272 // TODO(sleevi): Support CRLSet revocation. |
| 213 // TODO(svaldez): Add specific error codes for trust errors resulting from | |
| 214 // expired/not-yet-valid certs. | |
| 215 switch (trust_result) { | 273 switch (trust_result) { |
| 216 case kSecTrustResultUnspecified: | 274 case kSecTrustResultUnspecified: |
| 217 case kSecTrustResultProceed: | 275 case kSecTrustResultProceed: |
| 218 break; | 276 break; |
| 219 case kSecTrustResultDeny: | 277 case kSecTrustResultDeny: |
| 220 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; | 278 verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID; |
| 279 break; | |
| 221 default: | 280 default: |
| 222 verify_result->cert_status |= CERT_STATUS_INVALID; | 281 CFArrayRef properties = SecTrustCopyProperties(trust_ref); |
| 282 verify_result->cert_status |= GetFailureFromTrustProperties(properties); | |
| 223 } | 283 } |
| 224 | 284 |
| 285 GetCertChainInfo(final_chain, verify_result); | |
| 286 | |
| 225 // Perform hostname verification independent of SecTrustEvaluate. | 287 // Perform hostname verification independent of SecTrustEvaluate. |
| 226 if (!verify_result->verified_cert->VerifyNameMatch( | 288 if (!verify_result->verified_cert->VerifyNameMatch( |
| 227 hostname, &verify_result->common_name_fallback_used)) { | 289 hostname, &verify_result->common_name_fallback_used)) { |
| 228 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; | 290 verify_result->cert_status |= CERT_STATUS_COMMON_NAME_INVALID; |
| 229 } | 291 } |
| 230 | 292 |
| 231 verify_result->is_issued_by_known_root = false; | 293 verify_result->is_issued_by_known_root = false; |
| 232 | 294 |
| 233 if (IsCertStatusError(verify_result->cert_status)) | 295 if (IsCertStatusError(verify_result->cert_status)) |
| 234 return MapCertStatusToNetError(verify_result->cert_status); | 296 return MapCertStatusToNetError(verify_result->cert_status); |
| 235 | 297 |
| 236 return OK; | 298 return OK; |
| 237 } | 299 } |
| 238 | 300 |
| 239 } // namespace net | 301 } // namespace net |
| OLD | NEW |