Show More
@@ -114,6 +114,9 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 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 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 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 = |
|
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 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 |
|
222 | if settings['cafile'] is not None: | |
227 |
sslcontext.load_verify_locations(cafile= |
|
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