OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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_mac.h" | 5 #include "net/cert/cert_verify_proc_mac.h" |
6 | 6 |
7 #include <CommonCrypto/CommonDigest.h> | 7 #include <CommonCrypto/CommonDigest.h> |
8 #include <CoreServices/CoreServices.h> | 8 #include <CoreServices/CoreServices.h> |
9 #include <Security/Security.h> | 9 #include <Security/Security.h> |
10 | 10 |
(...skipping 159 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
170 // revocation preference. | 170 // revocation preference. |
171 status = x509_util::CreateRevocationPolicies( | 171 status = x509_util::CreateRevocationPolicies( |
172 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED), local_policies); | 172 (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED), local_policies); |
173 if (status) | 173 if (status) |
174 return status; | 174 return status; |
175 | 175 |
176 policies->reset(local_policies.release()); | 176 policies->reset(local_policies.release()); |
177 return noErr; | 177 return noErr; |
178 } | 178 } |
179 | 179 |
180 // Stores the constructed certificate chain |cert_chain| and information about | 180 // Stores the constructed certificate chain |cert_chain| into |
181 // the signature algorithms used into |*verify_result|. If the leaf cert in | 181 // |*verify_result|. |cert_chain| must not be empty. |
182 // |cert_chain| contains a weak (MD2, MD4, MD5, SHA-1) signature, stores that | 182 void CopyCertChainToVerifyResult(CFArrayRef cert_chain, |
183 // in |*leaf_is_weak|. |cert_chain| must not be empty. | 183 CertVerifyResult* verify_result) { |
184 void GetCertChainInfo(CFArrayRef cert_chain, | |
185 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info, | |
186 CertVerifyResult* verify_result, | |
187 bool* leaf_is_weak) { | |
188 DCHECK_LT(0, CFArrayGetCount(cert_chain)); | 184 DCHECK_LT(0, CFArrayGetCount(cert_chain)); |
189 | 185 |
190 *leaf_is_weak = false; | |
191 verify_result->has_md2 = false; | |
192 verify_result->has_md4 = false; | |
193 verify_result->has_md5 = false; | |
194 verify_result->has_sha1 = false; | |
195 verify_result->has_sha1_leaf = false; | |
196 | |
197 SecCertificateRef verified_cert = NULL; | 186 SecCertificateRef verified_cert = NULL; |
198 std::vector<SecCertificateRef> verified_chain; | 187 std::vector<SecCertificateRef> verified_chain; |
199 for (CFIndex i = 0, count = CFArrayGetCount(cert_chain); i < count; ++i) { | 188 for (CFIndex i = 0, count = CFArrayGetCount(cert_chain); i < count; ++i) { |
200 SecCertificateRef chain_cert = reinterpret_cast<SecCertificateRef>( | 189 SecCertificateRef chain_cert = reinterpret_cast<SecCertificateRef>( |
201 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); | 190 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); |
202 if (i == 0) { | 191 if (i == 0) { |
203 verified_cert = chain_cert; | 192 verified_cert = chain_cert; |
204 } else { | 193 } else { |
205 verified_chain.push_back(chain_cert); | 194 verified_chain.push_back(chain_cert); |
206 } | 195 } |
| 196 } |
| 197 if (!verified_cert) { |
| 198 NOTREACHED(); |
| 199 return; |
| 200 } |
| 201 |
| 202 verify_result->verified_cert = |
| 203 X509Certificate::CreateFromHandle(verified_cert, verified_chain); |
| 204 } |
| 205 |
| 206 // Returns true if the intermediates (excluding trusted certificates) use a |
| 207 // weak hashing algorithm, but the target does not use a weak hash. |
| 208 bool IsWeakChainBasedOnHashingAlgorithms( |
| 209 CFArrayRef cert_chain, |
| 210 CSSM_TP_APPLE_EVIDENCE_INFO* chain_info) { |
| 211 DCHECK_LT(0, CFArrayGetCount(cert_chain)); |
| 212 |
| 213 bool intermediates_contain_weak_hash = false; |
| 214 bool leaf_uses_weak_hash = false; |
| 215 |
| 216 for (CFIndex i = 0, count = CFArrayGetCount(cert_chain); i < count; ++i) { |
| 217 SecCertificateRef chain_cert = reinterpret_cast<SecCertificateRef>( |
| 218 const_cast<void*>(CFArrayGetValueAtIndex(cert_chain, i))); |
207 | 219 |
208 if ((chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_IN_ANCHORS) || | 220 if ((chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_IN_ANCHORS) || |
209 (chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_ROOT)) { | 221 (chain_info[i].StatusBits & CSSM_CERT_STATUS_IS_ROOT)) { |
210 // The current certificate is either in the user's trusted store or is | 222 // The current certificate is either in the user's trusted store or is |
211 // a root (self-signed) certificate. Ignore the signature algorithm for | 223 // a root (self-signed) certificate. Ignore the signature algorithm for |
212 // these certificates, as it is meaningless for security. We allow | 224 // these certificates, as it is meaningless for security. We allow |
213 // self-signed certificates (i == 0 & IS_ROOT), since we accept that | 225 // self-signed certificates (i == 0 & IS_ROOT), since we accept that |
214 // any security assertions by such a cert are inherently meaningless. | 226 // any security assertions by such a cert are inherently meaningless. |
215 continue; | 227 continue; |
216 } | 228 } |
217 | 229 |
218 bool is_leaf = i == 0; | |
219 X509Certificate::SignatureHashAlgorithm hash_algorithm = | 230 X509Certificate::SignatureHashAlgorithm hash_algorithm = |
220 FillCertVerifyResultWeakSignature(chain_cert, is_leaf, verify_result); | 231 X509Certificate::GetSignatureHashAlgorithm(chain_cert); |
221 if (is_leaf) { | 232 |
222 switch (hash_algorithm) { | 233 switch (hash_algorithm) { |
223 case X509Certificate::kSignatureHashAlgorithmMd2: | 234 case X509Certificate::kSignatureHashAlgorithmMd2: |
224 case X509Certificate::kSignatureHashAlgorithmMd4: | 235 case X509Certificate::kSignatureHashAlgorithmMd4: |
225 case X509Certificate::kSignatureHashAlgorithmMd5: | 236 case X509Certificate::kSignatureHashAlgorithmMd5: |
226 case X509Certificate::kSignatureHashAlgorithmSha1: | 237 case X509Certificate::kSignatureHashAlgorithmSha1: |
227 *leaf_is_weak = true; | 238 if (i == 0) { |
228 break; | 239 leaf_uses_weak_hash = true; |
229 case X509Certificate::kSignatureHashAlgorithmOther: | 240 } else { |
230 break; | 241 intermediates_contain_weak_hash = true; |
231 } | 242 } |
| 243 break; |
| 244 case X509Certificate::kSignatureHashAlgorithmOther: |
| 245 break; |
232 } | 246 } |
233 } | 247 } |
234 if (!verified_cert) { | |
235 NOTREACHED(); | |
236 return; | |
237 } | |
238 | 248 |
239 verify_result->verified_cert = | 249 return !leaf_uses_weak_hash && intermediates_contain_weak_hash; |
240 X509Certificate::CreateFromHandle(verified_cert, verified_chain); | |
241 } | 250 } |
242 | 251 |
243 using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>; | 252 using ExtensionsMap = std::map<net::der::Input, net::ParsedExtension>; |
244 | 253 |
245 // Helper that looks up an extension by OID given a map of extensions. | 254 // Helper that looks up an extension by OID given a map of extensions. |
246 bool GetExtensionValue(const ExtensionsMap& extensions, | 255 bool GetExtensionValue(const ExtensionsMap& extensions, |
247 const net::der::Input& oid, | 256 const net::der::Input& oid, |
248 net::der::Input* value) { | 257 net::der::Input* value) { |
249 auto it = extensions.find(oid); | 258 auto it = extensions.find(oid); |
250 if (it == extensions.end()) | 259 if (it == extensions.end()) |
(...skipping 556 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
807 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified && | 816 bool untrusted = (temp_trust_result != kSecTrustResultUnspecified && |
808 temp_trust_result != kSecTrustResultProceed) || | 817 temp_trust_result != kSecTrustResultProceed) || |
809 crl_result == kCRLSetRevoked; | 818 crl_result == kCRLSetRevoked; |
810 bool weak_chain = false; | 819 bool weak_chain = false; |
811 if (CFArrayGetCount(temp_chain) == 0) { | 820 if (CFArrayGetCount(temp_chain) == 0) { |
812 // If the chain is empty, it cannot be trusted or have recoverable | 821 // If the chain is empty, it cannot be trusted or have recoverable |
813 // errors. | 822 // errors. |
814 DCHECK(untrusted); | 823 DCHECK(untrusted); |
815 DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result); | 824 DCHECK_NE(kSecTrustResultRecoverableTrustFailure, temp_trust_result); |
816 } else { | 825 } else { |
817 CertVerifyResult temp_verify_result; | |
818 bool leaf_is_weak = false; | |
819 GetCertChainInfo(temp_chain, temp_chain_info, &temp_verify_result, | |
820 &leaf_is_weak); | |
821 weak_chain = | 826 weak_chain = |
822 !leaf_is_weak && | 827 IsWeakChainBasedOnHashingAlgorithms(temp_chain, temp_chain_info); |
823 (temp_verify_result.has_md2 || temp_verify_result.has_md4 || | |
824 temp_verify_result.has_md5 || temp_verify_result.has_sha1); | |
825 } | 828 } |
826 // Set the result to the current chain if: | 829 // Set the result to the current chain if: |
827 // - This is the first verification attempt. This ensures that if | 830 // - This is the first verification attempt. This ensures that if |
828 // everything is awful (e.g. it may just be an untrusted cert), that | 831 // everything is awful (e.g. it may just be an untrusted cert), that |
829 // what is reported is exactly what was sent by the server | 832 // what is reported is exactly what was sent by the server |
830 // - If the current chain is trusted, and the old chain was not trusted, | 833 // - If the current chain is trusted, and the old chain was not trusted, |
831 // then prefer this chain. This ensures that if there is at least a | 834 // then prefer this chain. This ensures that if there is at least a |
832 // valid path to a trust anchor, it's preferred over reporting an error. | 835 // valid path to a trust anchor, it's preferred over reporting an error. |
833 // - If the current chain is trusted, and the old chain is trusted, but | 836 // - If the current chain is trusted, and the old chain is trusted, but |
834 // the old chain contained weak algorithms while the current chain only | 837 // the old chain contained weak algorithms while the current chain only |
(...skipping 24 matching lines...) Expand all Loading... |
859 break; | 862 break; |
860 } | 863 } |
861 | 864 |
862 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) | 865 if (flags & CertVerifier::VERIFY_REV_CHECKING_ENABLED) |
863 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; | 866 verify_result->cert_status |= CERT_STATUS_REV_CHECKING_ENABLED; |
864 | 867 |
865 if (*completed_chain_crl_result == kCRLSetRevoked) | 868 if (*completed_chain_crl_result == kCRLSetRevoked) |
866 verify_result->cert_status |= CERT_STATUS_REVOKED; | 869 verify_result->cert_status |= CERT_STATUS_REVOKED; |
867 | 870 |
868 if (CFArrayGetCount(completed_chain) > 0) { | 871 if (CFArrayGetCount(completed_chain) > 0) { |
869 bool leaf_is_weak_unused = false; | 872 CopyCertChainToVerifyResult(completed_chain, verify_result); |
870 GetCertChainInfo(completed_chain, chain_info, verify_result, | |
871 &leaf_is_weak_unused); | |
872 } | 873 } |
873 | 874 |
874 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits | 875 // As of Security Update 2012-002/OS X 10.7.4, when an RSA key < 1024 bits |
875 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds | 876 // is encountered, CSSM returns CSSMERR_TP_VERIFY_ACTION_FAILED and adds |
876 // CSSMERR_CSP_UNSUPPORTED_KEY_SIZE as a certificate status. Avoid mapping | 877 // CSSMERR_CSP_UNSUPPORTED_KEY_SIZE as a certificate status. Avoid mapping |
877 // the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only | 878 // the CSSMERR_TP_VERIFY_ACTION_FAILED to CERT_STATUS_INVALID if the only |
878 // error was due to an unsupported key size. | 879 // error was due to an unsupported key size. |
879 bool policy_failed = false; | 880 bool policy_failed = false; |
880 bool policy_fail_already_mapped = false; | 881 bool policy_fail_already_mapped = false; |
881 bool weak_key_or_signature_algorithm = false; | 882 bool weak_key_or_signature_algorithm = false; |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1074 // EV cert and it was covered by CRLSets or revocation checking passed. | 1075 // EV cert and it was covered by CRLSets or revocation checking passed. |
1075 verify_result->cert_status |= CERT_STATUS_IS_EV; | 1076 verify_result->cert_status |= CERT_STATUS_IS_EV; |
1076 } | 1077 } |
1077 | 1078 |
1078 return OK; | 1079 return OK; |
1079 } | 1080 } |
1080 | 1081 |
1081 } // namespace net | 1082 } // namespace net |
1082 | 1083 |
1083 #pragma clang diagnostic pop // "-Wdeprecated-declarations" | 1084 #pragma clang diagnostic pop // "-Wdeprecated-declarations" |
OLD | NEW |