Web Inspector: Network: add button to show system certificate dialog
[WebKit-https.git] / Source / WebCore / platform / network / cf / CertificateInfoCFNet.cpp
1 /*
2  * Copyright (C) 2010, 2015 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "CertificateInfo.h"
28
29 namespace WebCore {
30
31 #if PLATFORM(COCOA)
32 RetainPtr<CFArrayRef> CertificateInfo::certificateChainFromSecTrust(SecTrustRef trust)
33 {
34     auto count = SecTrustGetCertificateCount(trust);
35     auto certificateChain = CFArrayCreateMutable(0, count, &kCFTypeArrayCallBacks);
36     for (CFIndex i = 0; i < count; i++)
37         CFArrayAppendValue(certificateChain, SecTrustGetCertificateAtIndex(trust, i));
38     return adoptCF((CFArrayRef)certificateChain);
39 }
40 #endif
41
42 CertificateInfo::Type CertificateInfo::type() const
43 {
44 #if HAVE(SEC_TRUST_SERIALIZATION)
45     if (m_trust)
46         return Type::Trust;
47 #endif
48     if (m_certificateChain)
49         return Type::CertificateChain;
50     return Type::None;
51 }
52
53 CFArrayRef CertificateInfo::certificateChain() const
54 {
55 #if HAVE(SEC_TRUST_SERIALIZATION)
56     if (m_certificateChain)
57         return m_certificateChain.get();
58
59     if (m_trust) 
60         m_certificateChain = CertificateInfo::certificateChainFromSecTrust(m_trust.get());
61 #endif
62
63     return m_certificateChain.get();
64 }
65
66 bool CertificateInfo::containsNonRootSHA1SignedCertificate() const
67 {
68 #if HAVE(SEC_TRUST_SERIALIZATION)
69     if (m_trust) {
70         // Allow only the root certificate (the last in the chain) to be SHA1.
71         for (CFIndex i = 0, size = SecTrustGetCertificateCount(trust()) - 1; i < size; ++i) {
72             auto certificate = SecTrustGetCertificateAtIndex(trust(), i);
73             if (SecCertificateGetSignatureHashAlgorithm(certificate) == kSecSignatureHashAlgorithmSHA1)
74                 return true;
75         }
76
77         return false;
78     }
79 #endif
80
81 #if PLATFORM(COCOA)
82     if (m_certificateChain) {
83         // Allow only the root certificate (the last in the chain) to be SHA1.
84         for (CFIndex i = 0, size = CFArrayGetCount(m_certificateChain.get()) - 1; i < size; ++i) {
85             auto certificate = checked_cf_cast<SecCertificateRef>(CFArrayGetValueAtIndex(m_certificateChain.get(), i));
86             if (SecCertificateGetSignatureHashAlgorithm(certificate) == kSecSignatureHashAlgorithmSHA1)
87                 return true;
88         }
89         return false;
90     }
91 #endif
92
93     return false;
94 }
95
96 std::optional<CertificateInfo::SummaryInfo> CertificateInfo::summaryInfo() const
97 {
98     auto chain = certificateChain();
99     if (!chain)
100         return std::nullopt;
101
102     SummaryInfo summaryInfo;
103
104 #if PLATFORM(COCOA) && !PLATFORM(IOS_FAMILY_SIMULATOR) && !PLATFORM(IOSMAC)
105     auto leafCertificate = checked_cf_cast<SecCertificateRef>(CFArrayGetValueAtIndex(chain, 0));
106
107     auto subjectCF = adoptCF(SecCertificateCopySubjectSummary(leafCertificate));
108     summaryInfo.subject = subjectCF.get();
109 #endif
110
111 #if PLATFORM(MAC)
112     if (auto certificateDictionary = adoptCF(SecCertificateCopyValues(leafCertificate, nullptr, nullptr))) {
113         // CFAbsoluteTime is relative to 01/01/1970 00:00:00 GMT.
114         const Seconds absoluteReferenceDate(978307200);
115
116         if (auto validNotBefore = checked_cf_cast<CFDictionaryRef>(CFDictionaryGetValue(certificateDictionary.get(), kSecOIDX509V1ValidityNotBefore))) {
117             if (auto number = checked_cf_cast<CFNumberRef>(CFDictionaryGetValue(validNotBefore, CFSTR("value")))) {
118                 double numberValue;
119                 if (CFNumberGetValue(number, kCFNumberDoubleType, &numberValue))
120                     summaryInfo.validFrom = absoluteReferenceDate + Seconds(numberValue);
121             }
122         }
123
124         if (auto validNotAfter = checked_cf_cast<CFDictionaryRef>(CFDictionaryGetValue(certificateDictionary.get(), kSecOIDX509V1ValidityNotAfter))) {
125             if (auto number = checked_cf_cast<CFNumberRef>(CFDictionaryGetValue(validNotAfter, CFSTR("value")))) {
126                 double numberValue;
127                 if (CFNumberGetValue(number, kCFNumberDoubleType, &numberValue))
128                     summaryInfo.validUntil = absoluteReferenceDate + Seconds(numberValue);
129             }
130         }
131
132         if (auto dnsNames = checked_cf_cast<CFDictionaryRef>(CFDictionaryGetValue(certificateDictionary.get(), CFSTR("DNSNAMES")))) {
133             if (auto dnsNamesArray = checked_cf_cast<CFArrayRef>(CFDictionaryGetValue(dnsNames, CFSTR("value")))) {
134                 for (CFIndex i = 0, count = CFArrayGetCount(dnsNamesArray); i < count; ++i) {
135                     if (auto dnsName = checked_cf_cast<CFStringRef>(CFArrayGetValueAtIndex(dnsNamesArray, i)))
136                         summaryInfo.dnsNames.append(dnsName);
137                 }
138             }
139         }
140
141         if (auto ipAddresses = checked_cf_cast<CFDictionaryRef>(CFDictionaryGetValue(certificateDictionary.get(), CFSTR("IPADDRESSES")))) {
142             if (auto ipAddressesArray = checked_cf_cast<CFArrayRef>(CFDictionaryGetValue(ipAddresses, CFSTR("value")))) {
143                 for (CFIndex i = 0, count = CFArrayGetCount(ipAddressesArray); i < count; ++i) {
144                     if (auto ipAddress = checked_cf_cast<CFStringRef>(CFArrayGetValueAtIndex(ipAddressesArray, i)))
145                         summaryInfo.ipAddresses.append(ipAddress);
146                 }
147             }
148         }
149     }
150 #endif
151
152     return summaryInfo;
153 }
154
155 } // namespace WebCore