##// END OF EJS Templates
sslutil: move CA file processing into _hostsettings()...
Gregory Szorc -
r29260:70bc9912 default
parent child Browse files
Show More
@@ -114,6 +114,9 b' def _hostsettings(ui, hostname):'
114 s = {
114 s = {
115 # List of 2-tuple of (hash algorithm, hash).
115 # List of 2-tuple of (hash algorithm, hash).
116 'certfingerprints': [],
116 'certfingerprints': [],
117 # Path to file containing concatenated CA certs. Used by
118 # SSLContext.load_verify_locations().
119 'cafile': None,
117 # ssl.CERT_* constant used by SSLContext.verify_mode.
120 # ssl.CERT_* constant used by SSLContext.verify_mode.
118 'verifymode': None,
121 'verifymode': None,
119 }
122 }
@@ -132,45 +135,39 b' def _hostsettings(ui, hostname):'
132 elif ui.insecureconnections:
135 elif ui.insecureconnections:
133 s['verifymode'] = ssl.CERT_NONE
136 s['verifymode'] = ssl.CERT_NONE
134
137
135 # TODO assert verifymode is not None once we integrate cacert
138 # Try to hook up CA certificate validation unless something above
136 # checking in this function.
139 # makes it not necessary.
140 if s['verifymode'] is None:
141 # Find global certificates file in config.
142 cafile = ui.config('web', 'cacerts')
143
144 if cafile:
145 cafile = util.expandpath(cafile)
146 if not os.path.exists(cafile):
147 raise error.Abort(_('could not find web.cacerts: %s') % cafile)
148 else:
149 # No global CA certs. See if we can load defaults.
150 cafile = _defaultcacerts()
151 if cafile:
152 ui.debug('using %s to enable OS X system CA\n' % cafile)
153
154 s['cafile'] = cafile
155
156 # Require certificate validation if CA certs are being loaded and
157 # verification hasn't been disabled above.
158 if cafile or _canloaddefaultcerts:
159 s['verifymode'] = ssl.CERT_REQUIRED
160 else:
161 # At this point we don't have a fingerprint, aren't being
162 # explicitly insecure, and can't load CA certs. Connecting
163 # at this point is insecure. But we do it for BC reasons.
164 # TODO abort here to make secure by default.
165 s['verifymode'] = ssl.CERT_NONE
166
167 assert s['verifymode'] is not None
137
168
138 return s
169 return s
139
170
140 def _determinecertoptions(ui, settings):
141 """Determine certificate options for a connections.
142
143 Returns a tuple of (cert_reqs, ca_certs).
144 """
145 if settings['verifymode'] == ssl.CERT_NONE:
146 return ssl.CERT_NONE, None
147
148 cacerts = ui.config('web', 'cacerts')
149
150 # If a value is set in the config, validate against a path and load
151 # and require those certs.
152 if cacerts:
153 cacerts = util.expandpath(cacerts)
154 if not os.path.exists(cacerts):
155 raise error.Abort(_('could not find web.cacerts: %s') % cacerts)
156
157 return ssl.CERT_REQUIRED, cacerts
158
159 # No CAs in config. See if we can load defaults.
160 cacerts = _defaultcacerts()
161
162 # We found an alternate CA bundle to use. Load it.
163 if cacerts:
164 ui.debug('using %s to enable OS X system CA\n' % cacerts)
165 ui.setconfig('web', 'cacerts', cacerts, 'defaultcacerts')
166 return ssl.CERT_REQUIRED, cacerts
167
168 # FUTURE this can disappear once wrapsocket() is secure by default.
169 if _canloaddefaultcerts:
170 return ssl.CERT_REQUIRED, None
171
172 return ssl.CERT_NONE, None
173
174 def wrapsocket(sock, keyfile, certfile, ui, serverhostname=None):
171 def wrapsocket(sock, keyfile, certfile, ui, serverhostname=None):
175 """Add SSL/TLS to a socket.
172 """Add SSL/TLS to a socket.
176
173
@@ -188,7 +185,6 b' def wrapsocket(sock, keyfile, certfile, '
188 raise error.Abort('serverhostname argument is required')
185 raise error.Abort('serverhostname argument is required')
189
186
190 settings = _hostsettings(ui, serverhostname)
187 settings = _hostsettings(ui, serverhostname)
191 cert_reqs, ca_certs = _determinecertoptions(ui, settings)
192
188
193 # Despite its name, PROTOCOL_SSLv23 selects the highest protocol
189 # Despite its name, PROTOCOL_SSLv23 selects the highest protocol
194 # that both ends support, including TLS protocols. On legacy stacks,
190 # that both ends support, including TLS protocols. On legacy stacks,
@@ -215,7 +211,7 b' def wrapsocket(sock, keyfile, certfile, '
215 sslcontext.options |= OP_NO_SSLv2 | OP_NO_SSLv3
211 sslcontext.options |= OP_NO_SSLv2 | OP_NO_SSLv3
216
212
217 # This still works on our fake SSLContext.
213 # This still works on our fake SSLContext.
218 sslcontext.verify_mode = cert_reqs
214 sslcontext.verify_mode = settings['verifymode']
219
215
220 if certfile is not None:
216 if certfile is not None:
221 def password():
217 def password():
@@ -223,8 +219,8 b' def wrapsocket(sock, keyfile, certfile, '
223 return ui.getpass(_('passphrase for %s: ') % f, '')
219 return ui.getpass(_('passphrase for %s: ') % f, '')
224 sslcontext.load_cert_chain(certfile, keyfile, password)
220 sslcontext.load_cert_chain(certfile, keyfile, password)
225
221
226 if ca_certs is not None:
222 if settings['cafile'] is not None:
227 sslcontext.load_verify_locations(cafile=ca_certs)
223 sslcontext.load_verify_locations(cafile=settings['cafile'])
228 caloaded = True
224 caloaded = True
229 else:
225 else:
230 # This is a no-op on old Python.
226 # This is a no-op on old Python.
General Comments 0
You need to be logged in to leave comments. Login now