f8f97555c3a4b71d15f7417c1494164a3d8b3916
[WebKit-https.git] / Source / WebCore / platform / network / curl / SSLHandle.cpp
1 /*
2  * Copyright (C) 2013 University of Szeged
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 UNIVERSITY OF SZEGED ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27
28 #if USE(CURL)
29
30 #include "SSLHandle.h"
31
32 #include "ResourceHandleInternal.h"
33
34 #include <openssl/pem.h>
35 #include <openssl/ssl.h>
36 #include <openssl/x509_vfy.h>
37 #include <wtf/ListHashSet.h>
38 #include <wtf/NeverDestroyed.h>
39 #include <wtf/text/CString.h>
40
41 namespace WebCore {
42
43 typedef std::tuple<String, String> clientCertificate;
44
45 static HashMap<String, ListHashSet<String>, ASCIICaseInsensitiveHash>& allowedHosts()
46 {
47     static NeverDestroyed<HashMap<String, ListHashSet<String>, ASCIICaseInsensitiveHash>> map;
48     return map;
49 }
50
51 static HashMap<String, clientCertificate, ASCIICaseInsensitiveHash>& allowedClientHosts()
52 {
53     static NeverDestroyed<HashMap<String, clientCertificate, ASCIICaseInsensitiveHash>> map;
54     return map;
55 }
56
57 void allowsAnyHTTPSCertificateHosts(const String& host)
58 {
59     ListHashSet<String> certificates;
60     allowedHosts().set(host, certificates);
61 }
62
63 void addAllowedClientCertificate(const String& host, const String& certificate, const String& key)
64 {
65     clientCertificate clientInfo(certificate, key);
66     allowedClientHosts().set(host, clientInfo);
67 }
68
69 void setSSLClientCertificate(ResourceHandle* handle)
70 {
71     String host = handle->firstRequest().url().host();
72     auto it = allowedClientHosts().find(host);
73     if (it == allowedClientHosts().end())
74         return;
75
76     ResourceHandleInternal* d = handle->getInternal();
77     clientCertificate clientInfo = it->value;
78
79     d->m_curlHandle.setSslCert(std::get<0>(clientInfo).utf8().data());
80     d->m_curlHandle.setSslCertType("P12");
81     d->m_curlHandle.setSslKeyPassword(std::get<1>(clientInfo).utf8().data());
82 }
83
84 bool sslIgnoreHTTPSCertificate(const String& host, const ListHashSet<String>& certificates)
85 {
86     auto it = allowedHosts().find(host);
87     if (it != allowedHosts().end()) {
88         if ((it->value).isEmpty()) {
89             it->value = certificates;
90             return true;
91         }
92         if (certificates.size() != it->value.size())
93             return false;
94         auto certsIter = certificates.begin();
95         auto valueIter = (it->value).begin();
96         for (; valueIter != (it->value).end(); ++valueIter, ++certsIter) {
97             if (*certsIter != *valueIter)
98                 return false;
99         }
100         return true;
101     }
102     return false;
103 }
104
105 unsigned sslCertificateFlag(const unsigned& sslError)
106 {
107     switch (sslError) {
108     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT : // the issuer certificate could not be found: this occurs if the issuer certificate of an untrusted certificate cannot be found.
109     case X509_V_ERR_UNABLE_TO_GET_CRL : // the CRL of a certificate could not be found.
110     case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY : // the issuer certificate of a locally looked up certificate could not be found. This normally means the list of trusted certificates is not complete.
111         return SSL_CERTIFICATE_UNKNOWN_CA;
112     case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE : // the certificate signature could not be decrypted. This means that the actual signature value could not be determined rather than it not matching the expected value, this is only meaningful for RSA keys.
113     case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE : // the CRL signature could not be decrypted: this means that the actual signature value could not be determined rather than it not matching the expected value. Unused.
114     case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY : // the public key in the certificate SubjectPublicKeyInfo could not be read.
115     case X509_V_ERR_CERT_SIGNATURE_FAILURE : // the signature of the certificate is invalid.
116     case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT : // the passed certificate is self signed and the same certificate cannot be found in the list of trusted certificates.
117     case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN : // the certificate chain could be built up using the untrusted certificates but the root could not be found locally.
118     case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE : // no signatures could be verified because the chain contains only one certificate and it is not self signed.
119     case X509_V_ERR_INVALID_PURPOSE : // the supplied certificate cannot be used for the specified purpose.
120     case X509_V_ERR_CERT_UNTRUSTED : // the root CA is not marked as trusted for the specified purpose.
121     case X509_V_ERR_CERT_REJECTED : // the root CA is marked to reject the specified purpose.
122     case X509_V_ERR_NO_EXPLICIT_POLICY : // the verification flags were set to require and explicit policy but none was present.
123     case X509_V_ERR_DIFFERENT_CRL_SCOPE : // the only CRLs that could be found did not match the scope of the certificate.
124         return SSL_CERTIFICATE_INSECURE;
125     case X509_V_ERR_CERT_NOT_YET_VALID : // the certificate is not yet valid: the notBefore date is after the current time.
126     case X509_V_ERR_CRL_NOT_YET_VALID : // the CRL is not yet valid.
127         return SSL_CERTIFICATE_NOT_ACTIVATED;
128     case X509_V_ERR_CERT_HAS_EXPIRED : // the certificate has expired: that is the notAfter date is before the current time.
129     case X509_V_ERR_CRL_HAS_EXPIRED : // the CRL has expired.
130         return SSL_CERTIFICATE_EXPIRED;
131     case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD : // the certificate notBefore field contains an invalid time.
132     case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD : // the certificate notAfter field contains an invalid time.
133     case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD : // the CRL lastUpdate field contains an invalid time.
134     case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD : // the CRL nextUpdate field contains an invalid time.
135     case X509_V_ERR_OUT_OF_MEM : // an error occurred trying to allocate memory. This should never happen.
136     case X509_V_ERR_CERT_CHAIN_TOO_LONG : // the certificate chain length is greater than the supplied maximum depth. Unused.
137     case X509_V_ERR_PATH_LENGTH_EXCEEDED : // the basicConstraints pathlength parameter has been exceeded.
138     case X509_V_ERR_INVALID_EXTENSION : // a certificate extension had an invalid value (for example an incorrect encoding) or some value inconsistent with other extensions.
139     case X509_V_ERR_INVALID_POLICY_EXTENSION : // a certificate policies extension had an invalid value (for example an incorrect encoding) or some value inconsistent with other extensions. This error only occurs if policy processing is enabled.
140     case X509_V_ERR_UNSUPPORTED_EXTENSION_FEATURE : // some feature of a certificate extension is not supported. Unused.
141     case X509_V_ERR_PERMITTED_VIOLATION : // a name constraint violation occured in the permitted subtrees.
142     case X509_V_ERR_EXCLUDED_VIOLATION : // a name constraint violation occured in the excluded subtrees.
143     case X509_V_ERR_SUBTREE_MINMAX : // a certificate name constraints extension included a minimum or maximum field: this is not supported.
144     case X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE : // an unsupported name constraint type was encountered. OpenSSL currently only supports directory name, DNS name, email and URI types.
145     case X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX : // the format of the name constraint is not recognised: for example an email address format of a form not mentioned in RFC3280. This could be caused by a garbage extension or some new feature not currently supported.
146     case X509_V_ERR_CRL_PATH_VALIDATION_ERROR : // an error occured when attempting to verify the CRL path. This error can only happen if extended CRL checking is enabled.
147     case X509_V_ERR_APPLICATION_VERIFICATION : // an application specific error. This will never be returned unless explicitly set by an application.
148         return SSL_CERTIFICATE_GENERIC_ERROR;
149     case X509_V_ERR_CERT_REVOKED : // the certificate has been revoked.
150         return SSL_CERTIFICATE_REVOKED;
151     case X509_V_ERR_INVALID_CA : // a CA certificate is invalid. Either it is not a CA or its extensions are not consistent with the supplied purpose.
152     case X509_V_ERR_SUBJECT_ISSUER_MISMATCH : // the current candidate issuer certificate was rejected because its subject name did not match the issuer name of the current certificate. This is only set if issuer check debugging is enabled it is used for status notification and is not in itself an error.
153     case X509_V_ERR_AKID_SKID_MISMATCH : // the current candidate issuer certificate was rejected because its subject key identifier was present and did not match the authority key identifier current certificate. This is only set if issuer check debugging is enabled it is used for status notification and is not in itself an error.
154     case X509_V_ERR_AKID_ISSUER_SERIAL_MISMATCH : // the current candidate issuer certificate was rejected because its issuer name and serial number was present and did not match the authority key identifier of the current certificate. This is only set if issuer check debugging is enabled it is used for status notification and is not in itself an error.
155     case X509_V_ERR_KEYUSAGE_NO_CERTSIGN : // the current candidate issuer certificate was rejected because its keyUsage extension does not permit certificate signing. This is only set if issuer check debugging is enabled it is used for status notification and is not in itself an error.
156         return SSL_CERTIFICATE_BAD_IDENTITY;
157     default :
158         return SSL_CERTIFICATE_GENERIC_ERROR;
159     }
160 }
161
162 #if !PLATFORM(WIN)
163 // success of certificates extraction
164 bool pemData(X509_STORE_CTX* ctx, ListHashSet<String>& certificates)
165 {
166     bool ok = true;
167     STACK_OF(X509)* certs = X509_STORE_CTX_get1_chain(ctx);
168     for (int i = 0; i < sk_X509_num(certs); i++) {
169         X509* uCert = sk_X509_value(certs, i);
170         BIO* bio = BIO_new(BIO_s_mem());
171         int res = PEM_write_bio_X509(bio, uCert);
172         if (!res) {
173             ok = false;
174             BIO_free(bio);
175             break;
176         }
177
178         unsigned char* certificateData;
179         long length = BIO_get_mem_data(bio, &certificateData);
180         if (length < 0) {
181             ok = false;
182             BIO_free(bio);
183             break;
184         }
185
186         certificateData[length] = '\0';
187         String certificate = certificateData;
188         certificates.add(certificate);
189         BIO_free(bio);
190     }
191         sk_X509_pop_free(certs, X509_free);
192         return ok;
193 }
194 #endif
195
196 static int certVerifyCallback(int ok, X509_STORE_CTX* ctx)
197 {
198     // whether the verification of the certificate in question was passed (preverify_ok=1) or not (preverify_ok=0)
199
200     unsigned err = X509_STORE_CTX_get_error(ctx);
201     if (!err)
202         return 1;
203
204     SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
205     SSL_CTX* sslctx = SSL_get_SSL_CTX(ssl);
206     ResourceHandle* job = reinterpret_cast<ResourceHandle*>(SSL_CTX_get_app_data(sslctx));
207     String host = job->firstRequest().url().host();
208     ResourceHandleInternal* d = job->getInternal();
209
210     d->m_sslErrors = sslCertificateFlag(err);
211
212 #if PLATFORM(WIN)
213     auto it = allowedHosts().find(host);
214     ok = (it != allowedHosts().end());
215 #else
216     ListHashSet<String> certificates;
217     if (!pemData(ctx, certificates))
218         return 0;
219     ok = sslIgnoreHTTPSCertificate(host, certificates);
220 #endif
221
222     if (ok) {
223         // if the host and the certificate are stored for the current handle that means is enabled,
224         // so don't need to curl verifies the authenticity of the peer's certificate
225         d->m_curlHandle.setSslVerifyPeer(CurlHandle::VerifyPeerDisable);
226     }
227     return ok;
228 }
229
230 static CURLcode sslctxfun(CURL* curl, void* sslctx, void* parm)
231 {
232     SSL_CTX_set_app_data(reinterpret_cast<SSL_CTX*>(sslctx), parm);
233     SSL_CTX_set_verify(reinterpret_cast<SSL_CTX*>(sslctx), SSL_VERIFY_PEER, certVerifyCallback);
234     return CURLE_OK;
235 }
236
237 void setSSLVerifyOptions(ResourceHandle* handle)
238 {
239     ResourceHandleInternal* d = handle->getInternal();
240
241     d->m_curlHandle.setSslCtxCallbackFunction(sslctxfun, handle);
242 }
243
244 }
245
246 #endif