Merge lp:~vila/bzr/920455-ssl-defaults into lp:bzr/2.5
- 920455-ssl-defaults
- Merge into 2.5
Status: | Merged |
---|---|
Approved by: | Martin Packman |
Approved revision: | no longer in the source branch. |
Merged at revision: | 6468 |
Proposed branch: | lp:~vila/bzr/920455-ssl-defaults |
Merge into: | lp:bzr/2.5 |
Diff against target: |
242 lines (+67/-47) (has conflicts) 4 files modified
bzrlib/errors.py (+2/-1) bzrlib/tests/test_https_urllib.py (+8/-17) bzrlib/transport/http/_urllib2_wrappers.py (+50/-29) doc/en/release-notes/bzr-2.5.txt (+7/-0) Text conflict in doc/en/release-notes/bzr-2.5.txt |
To merge this branch: | bzr merge lp:~vila/bzr/920455-ssl-defaults |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Martin Packman (community) | Approve | ||
Gordon Tyler | Pending | ||
Jelmer Vernooij | Pending | ||
Review via email: mp+90693@code.launchpad.net |
This proposal supersedes a proposal from 2012-01-25.
Commit message
Provide an ``ssl.ca_certs`` default value for supported platforms.
Description of the change
Resubmitting a slightly simpler implementation to ensure we're still agreeing, see my replies to previous reviews too.
This add default values for the ssl.ca_certs config option pointing to the
most probable place where the certificates are place for supported
platforms.
Feedback needed from windows and osx packagers unless we rely on them to fix
it when building 2.5.0...
I've changed the tests so at least test_default_exists
bzrlib/
I've also change the option to fail if a non-existing path is used and
changed the code to check the config option only if ssl.cert_reqs is not none.
With these changes, either:
- the certificates are there and they will be checked by default
- they are not but ssl.cert_reqs is none, no need to bother the user
especially since that is the obvious workaround for now if something goes
wrong with the verification,
- an error is raised if the user ask for verification but we can't find the
CAs.
Vincent Ladeuil (vila) wrote : Posted in a previous version of this proposal | # |
Martin Packman (gz) wrote : Posted in a previous version of this proposal | # |
So, on windows we're mostly stuffed because ideally we'd use the Internet Explorer certificate store, but that's a completely different interface to openssl and the cert dir used on nix systems.
The best we can do is bundle curl-ca-bundle.crt with the all-in-one installer like we did previously:
<http://
Then accept the fact branching over https will be broken for everyone else using a python installer or running setup.py themselves.
This is why I was picky about the error message given for the original change... unfortunately it's now just a ValueError and traceback due to the default config value being bad. This branch changes one of those but not the other.
Jelmer Vernooij (jelmer) wrote : Posted in a previous version of this proposal | # |
32 def test_specified_
33 path = os.path.
34 stack = self.get_
35 - self.warnings = []
36 - def warning(*args):
37 - self.warnings.
38 - self.overrideAt
39 - self.assertEqua
40 - stack.get(
41 - self.assertLeng
42 - self.assertCont
43 - "is not valid for \"ssl.ca_certs\"")
44 + self.assertRais
Should it really be an error if the ssl.ca_certs path doesn't exist? What if e.g. "ssl.ca_reqs = optional", it doesn't seem like it should be a problem if the ca_certs are missing.
default_ca_cert() seems to return "/etc/ssl/..." on Windows. This seems wrong in any case. I realize you've asked for feedback from the packagers, but I think we should raise ValueError or return None for now at least.
Vincent Ladeuil (vila) wrote : Posted in a previous version of this proposal | # |
> This is why I was picky about the error message given for the original
> change... unfortunately it's now just a ValueError and traceback due to the
> default config value being bad. This branch changes one of those but not the
> other.
No, please do try again (with this proposal):
bzr config --remove launchpad_username
bzr config ssl.ca_
vila:~/
bzr: ERROR: Bad value "/I-dont-exist" for option "ssl.ca_certs".
So you get a proper error message that we may want to clarify but you don't
get a traceback.
You got a traceback prior to this change because default_ca_certs() was
raising it which is why I changed the implementation as ValueError is caught
for the *_from_store() functions, not the _default() functions.
I could change the ConfigValueError message to include 'See bzr help
ssl.ca_certs' but we froze the strings for 2.5 so I'd rather do that for
trunk.
I'll file bugs for windows and osx installers to make sure a bundle is
included.
Vincent Ladeuil (vila) wrote : Posted in a previous version of this proposal | # |
> Review: Approve
> 32 def test_specified_
> 33 path = os.path.
> 34 stack = self.get_
> 35 - self.warnings = []
> 36 - def warning(*args):
> 37 - self.warnings.
> 38 - self.overrideAt
> 39 - self.assertEqua
> 40 - stack.get(
> 41 - self.assertLeng
> 42 - self.assertCont
> 43 - "is not valid for \"ssl.ca_certs\"")
> 44 + self.assertRais
> Should it really be an error if the ssl.ca_certs path doesn't
> exist? What if e.g. "ssl.ca_reqs = optional", it doesn't seem like
> it should be a problem if the ca_certs are missing.
Indeed ! That's why I also change the code to query the option only if
required ;)
> default_ca_cert() seems to return "/etc/ssl/..." on Windows. This
> seems wrong in any case.
Yes.
> I realize you've asked for feedback from the packagers, but I
> think we should raise ValueError or return None for now at least.
That's what will happen if the option is needed, see
ca_certs_
Jelmer Vernooij (jelmer) wrote : Posted in a previous version of this proposal | # |
On 01/30/2012 03:19 PM, Vincent Ladeuil wrote:
> > Review: Approve
> > 32 def test_specified_
> > 33 path = os.path.
> > 34 stack = self.get_
> > 35 - self.warnings = []
> > 36 - def warning(*args):
> > 37 - self.warnings.
> > 38 - self.overrideAt
> > 39 - self.assertEqua
> > 40 - stack.get(
> > 41 - self.assertLeng
> > 42 - self.assertCont
> > 43 - "is not valid for \"ssl.ca_certs\"")
> > 44 + self.assertRais
>
> > Should it really be an error if the ssl.ca_certs path doesn't
> > exist? What if e.g. "ssl.ca_reqs = optional", it doesn't seem like
> > it should be a problem if the ca_certs are missing.
>
> Indeed ! That's why I also change the code to query the option only if
> required ;)
You're (correctly) trying to retrieve the ca certs too if
ssl.ca_
becomes a terminal error. It shouldn't be if ssl.ca_
if ssl.ca_
>
>
> > I realize you've asked for feedback from the packagers, but I
> > think we should raise ValueError or return None for now at least.
>
> That's what will happen if the option is needed, see
> ca_certs_
I don't see how that's the case. We'll be trying to retrieve the ca
certs in that case and it'll cause ConfigOptionVal
(and bzr to be aborted), right?
Cheers,
Jelmer
Vincent Ladeuil (vila) wrote : | # |
> You're (correctly) trying to retrieve the ca certs too if
ssl.ca_
a terminal error. It shouldn't be if ssl.ca_
ssl.ca_
Right, trying to fix that led to too much complications which I want to
avoid for 2.5. So, as discussed on IRC, I've file http:/pad.
support 'optional' later and just removed it from the actual implementation.
... and I'll take care of the news conflicts when/if this proposal is approved ;)
Martin Packman (gz) wrote : | # |
Trying a value relative to sys.executable is right for the installer, but what is absolutely required is the pretty message in the case where there are no certs, rather than what I currently get with this branch:
C:\bzr\
bzr: ERROR: Bad value "C:\Dev\
That's no good to man or beast, if it can't validate the cert, it *must* say what needs fixing, and how to disable the validation. This nearly exists already, but the logic seems to have been broken so the "no valid trusted SSL CA certificates file set" message branch doesn't get hit:
<https:/
What I expect is something like:
>bzr info https:/
bzr: ERROR: No valid trusted SSL CA certificates file found.
See `bzr help ssl.ca_certs` for how to specify trusted CA certificates.
Pass -Ossl.cert_
We nearly have all the bits, they just need connecting and tidying up.
Martin Packman (gz) wrote : | # |
With changes, the output is now:
C:\bzr\
Value "C:\Dev\
No valid trusted SSL CA certificates file set. See 'bzr help ssl.ca_certs' for more information on setting trusted CAs.
bzr: ERROR: _ssl.c:331: No root certificates specified for verification of other-side certificates.
Still not totally ideal but is good enough and I an poke later when some other exception stuff is sorted.
Vincent Ladeuil (vila) wrote : | # |
sent to pqm by email
Preview Diff
1 | === modified file 'bzrlib/errors.py' | |||
2 | --- bzrlib/errors.py 2012-01-27 15:47:12 +0000 | |||
3 | +++ bzrlib/errors.py 2012-01-31 17:04:31 +0000 | |||
4 | @@ -1761,7 +1761,8 @@ | |||
5 | 1761 | 1761 | ||
6 | 1762 | class ConfigOptionValueError(BzrError): | 1762 | class ConfigOptionValueError(BzrError): |
7 | 1763 | 1763 | ||
9 | 1764 | _fmt = """Bad value "%(value)s" for option "%(name)s".""" | 1764 | _fmt = ('Bad value "%(value)s" for option "%(name)s".\n' |
10 | 1765 | 'See ``bzr help %(name)s``') | ||
11 | 1765 | 1766 | ||
12 | 1766 | def __init__(self, name, value): | 1767 | def __init__(self, name, value): |
13 | 1767 | BzrError.__init__(self, name=name, value=value) | 1768 | BzrError.__init__(self, name=name, value=value) |
14 | 1768 | 1769 | ||
15 | === modified file 'bzrlib/tests/test_https_urllib.py' | |||
16 | --- bzrlib/tests/test_https_urllib.py 2012-01-19 15:27:47 +0000 | |||
17 | +++ bzrlib/tests/test_https_urllib.py 2012-01-31 17:04:31 +0000 | |||
18 | @@ -1,4 +1,4 @@ | |||
20 | 1 | # Copyright (C) 2011 Canonical Ltd | 1 | # Copyright (C) 2011,2012 Canonical Ltd |
21 | 2 | # | 2 | # |
22 | 3 | # This program is free software; you can redistribute it and/or modify | 3 | # This program is free software; you can redistribute it and/or modify |
23 | 4 | # it under the terms of the GNU General Public License as published by | 4 | # it under the terms of the GNU General Public License as published by |
24 | @@ -41,18 +41,10 @@ | |||
25 | 41 | def get_stack(self, content): | 41 | def get_stack(self, content): |
26 | 42 | return config.MemoryStack(content.encode('utf-8')) | 42 | return config.MemoryStack(content.encode('utf-8')) |
27 | 43 | 43 | ||
28 | 44 | def test_default_raises_value_error(self): | ||
29 | 45 | stack = self.get_stack("") | ||
30 | 46 | self.overrideAttr(_urllib2_wrappers, "DEFAULT_CA_PATH", | ||
31 | 47 | "/i-do-not-exist") | ||
32 | 48 | self.assertRaises(ValueError, stack.get, 'ssl.ca_certs') | ||
33 | 49 | |||
34 | 50 | def test_default_exists(self): | 44 | def test_default_exists(self): |
36 | 51 | self.build_tree(['cacerts.pem']) | 45 | """Check that the default we provide exists for the tested platform.""" |
37 | 52 | stack = self.get_stack("") | 46 | stack = self.get_stack("") |
41 | 53 | path = os.path.join(self.test_dir, "cacerts.pem") | 47 | self.assertPathExists(stack.get('ssl.ca_certs')) |
39 | 54 | self.overrideAttr(_urllib2_wrappers, "DEFAULT_CA_PATH", path) | ||
40 | 55 | self.assertEquals(path, stack.get('ssl.ca_certs')) | ||
42 | 56 | 48 | ||
43 | 57 | def test_specified(self): | 49 | def test_specified(self): |
44 | 58 | self.build_tree(['cacerts.pem']) | 50 | self.build_tree(['cacerts.pem']) |
45 | @@ -61,14 +53,15 @@ | |||
46 | 61 | self.assertEquals(path, stack.get('ssl.ca_certs')) | 53 | self.assertEquals(path, stack.get('ssl.ca_certs')) |
47 | 62 | 54 | ||
48 | 63 | def test_specified_doesnt_exist(self): | 55 | def test_specified_doesnt_exist(self): |
51 | 64 | path = os.path.join(self.test_dir, "nonexisting.pem") | 56 | stack = self.get_stack('') |
52 | 65 | stack = self.get_stack("ssl.ca_certs = %s\n" % path) | 57 | # Disable the default value mechanism to force the behavior we want |
53 | 58 | self.overrideAttr(_urllib2_wrappers.opt_ssl_ca_certs, 'default', | ||
54 | 59 | os.path.join(self.test_dir, u"nonexisting.pem")) | ||
55 | 66 | self.warnings = [] | 60 | self.warnings = [] |
56 | 67 | def warning(*args): | 61 | def warning(*args): |
57 | 68 | self.warnings.append(args[0] % args[1:]) | 62 | self.warnings.append(args[0] % args[1:]) |
58 | 69 | self.overrideAttr(trace, 'warning', warning) | 63 | self.overrideAttr(trace, 'warning', warning) |
61 | 70 | self.assertEquals(_urllib2_wrappers.DEFAULT_CA_PATH, | 64 | self.assertEquals(None, stack.get('ssl.ca_certs')) |
60 | 71 | stack.get('ssl.ca_certs')) | ||
62 | 72 | self.assertLength(1, self.warnings) | 65 | self.assertLength(1, self.warnings) |
63 | 73 | self.assertContainsRe(self.warnings[0], | 66 | self.assertContainsRe(self.warnings[0], |
64 | 74 | "is not valid for \"ssl.ca_certs\"") | 67 | "is not valid for \"ssl.ca_certs\"") |
65 | @@ -83,8 +76,6 @@ | |||
66 | 83 | def test_from_string(self): | 76 | def test_from_string(self): |
67 | 84 | stack = config.MemoryStack("ssl.cert_reqs = none\n") | 77 | stack = config.MemoryStack("ssl.cert_reqs = none\n") |
68 | 85 | self.assertEquals(ssl.CERT_NONE, stack.get("ssl.cert_reqs")) | 78 | self.assertEquals(ssl.CERT_NONE, stack.get("ssl.cert_reqs")) |
69 | 86 | stack = config.MemoryStack("ssl.cert_reqs = optional\n") | ||
70 | 87 | self.assertEquals(ssl.CERT_OPTIONAL, stack.get("ssl.cert_reqs")) | ||
71 | 88 | stack = config.MemoryStack("ssl.cert_reqs = required\n") | 79 | stack = config.MemoryStack("ssl.cert_reqs = required\n") |
72 | 89 | self.assertEquals(ssl.CERT_REQUIRED, stack.get("ssl.cert_reqs")) | 80 | self.assertEquals(ssl.CERT_REQUIRED, stack.get("ssl.cert_reqs")) |
73 | 90 | stack = config.MemoryStack("ssl.cert_reqs = invalid\n") | 81 | stack = config.MemoryStack("ssl.cert_reqs = invalid\n") |
74 | 91 | 82 | ||
75 | === modified file 'bzrlib/transport/http/_urllib2_wrappers.py' | |||
76 | --- bzrlib/transport/http/_urllib2_wrappers.py 2012-01-20 09:19:14 +0000 | |||
77 | +++ bzrlib/transport/http/_urllib2_wrappers.py 2012-01-31 17:04:31 +0000 | |||
78 | @@ -1,4 +1,4 @@ | |||
80 | 1 | # Copyright (C) 2006-2011 Canonical Ltd | 1 | # Copyright (C) 2006-2012 Canonical Ltd |
81 | 2 | # | 2 | # |
82 | 3 | # This program is free software; you can redistribute it and/or modify | 3 | # This program is free software; you can redistribute it and/or modify |
83 | 4 | # it under the terms of the GNU General Public License as published by | 4 | # it under the terms of the GNU General Public License as published by |
84 | @@ -74,14 +74,36 @@ | |||
85 | 74 | import ssl | 74 | import ssl |
86 | 75 | """) | 75 | """) |
87 | 76 | 76 | ||
88 | 77 | DEFAULT_CA_PATH = u"/etc/ssl/certs/ca-certificates.crt" | ||
89 | 78 | 77 | ||
90 | 78 | # Note for packagers: if there is no package providing certs for your platform, | ||
91 | 79 | # the curl project produces http://curl.haxx.se/ca/cacert.pem weekly. | ||
92 | 80 | _ssl_ca_certs_known_locations = [ | ||
93 | 81 | u'/etc/ssl/certs/ca-certificates.crt', # Ubuntu/debian/gentoo | ||
94 | 82 | u'/etc/pki/tls/certs/ca-bundle.crt', # Fedora/CentOS/RH | ||
95 | 83 | u'/etc/ssl/ca-bundle.pem', # OpenSuse | ||
96 | 84 | u'/etc/ssl/cert.pem', # OpenSuse | ||
97 | 85 | u"/usr/local/share/certs/ca-root-nss.crt", # FreeBSD | ||
98 | 86 | # XXX: Needs checking, can't trust the interweb ;) -- vila 2012-01-25 | ||
99 | 87 | u'/etc/openssl/certs/ca-certificates.crt', # Solaris | ||
100 | 88 | ] | ||
101 | 79 | 89 | ||
102 | 80 | def default_ca_certs(): | 90 | def default_ca_certs(): |
107 | 81 | if not os.path.exists(DEFAULT_CA_PATH): | 91 | if sys.platform == 'win32': |
108 | 82 | raise ValueError("default ca certs path %s does not exist" % | 92 | return os.path.join(os.path.dirname(sys.executable), u"ca_bundle.crt") |
109 | 83 | DEFAULT_CA_PATH) | 93 | elif sys.platform == 'darwin': |
110 | 84 | return DEFAULT_CA_PATH | 94 | # FIXME: Needs some default value for osx, waiting for osx installers |
111 | 95 | # guys feedback -- vila 2012-01-25 | ||
112 | 96 | pass | ||
113 | 97 | else: | ||
114 | 98 | # Try known locations for friendly OSes providing the root certificates | ||
115 | 99 | # without making them hard to use for any https client. | ||
116 | 100 | for path in _ssl_ca_certs_known_locations: | ||
117 | 101 | if os.path.exists(path): | ||
118 | 102 | # First found wins | ||
119 | 103 | return path | ||
120 | 104 | # A default path that makes sense and will be mentioned in the error | ||
121 | 105 | # presented to the user, even if not correct for all platforms | ||
122 | 106 | return _ssl_ca_certs_known_locations[0] | ||
123 | 85 | 107 | ||
124 | 86 | 108 | ||
125 | 87 | def ca_certs_from_store(path): | 109 | def ca_certs_from_store(path): |
126 | @@ -90,16 +112,11 @@ | |||
127 | 90 | return path | 112 | return path |
128 | 91 | 113 | ||
129 | 92 | 114 | ||
130 | 93 | def default_cert_reqs(): | ||
131 | 94 | return u"required" | ||
132 | 95 | |||
133 | 96 | |||
134 | 97 | def cert_reqs_from_store(unicode_str): | 115 | def cert_reqs_from_store(unicode_str): |
135 | 98 | import ssl | 116 | import ssl |
136 | 99 | try: | 117 | try: |
137 | 100 | return { | 118 | return { |
138 | 101 | "required": ssl.CERT_REQUIRED, | 119 | "required": ssl.CERT_REQUIRED, |
139 | 102 | "optional": ssl.CERT_OPTIONAL, | ||
140 | 103 | "none": ssl.CERT_NONE | 120 | "none": ssl.CERT_NONE |
141 | 104 | }[unicode_str] | 121 | }[unicode_str] |
142 | 105 | except KeyError: | 122 | except KeyError: |
143 | @@ -112,10 +129,15 @@ | |||
144 | 112 | invalid='warning', | 129 | invalid='warning', |
145 | 113 | help="""\ | 130 | help="""\ |
146 | 114 | Path to certification authority certificates to trust. | 131 | Path to certification authority certificates to trust. |
147 | 132 | |||
148 | 133 | This should be a valid path to a bundle containing all root Certificate | ||
149 | 134 | Authorities used to verify an https server certificate. | ||
150 | 135 | |||
151 | 136 | Use ssl.cert_reqs=none to disable certificate verification. | ||
152 | 115 | """) | 137 | """) |
153 | 116 | 138 | ||
154 | 117 | opt_ssl_cert_reqs = config.Option('ssl.cert_reqs', | 139 | opt_ssl_cert_reqs = config.Option('ssl.cert_reqs', |
156 | 118 | default=default_cert_reqs, | 140 | default=u"required", |
157 | 119 | from_unicode=cert_reqs_from_store, | 141 | from_unicode=cert_reqs_from_store, |
158 | 120 | invalid='error', | 142 | invalid='error', |
159 | 121 | help="""\ | 143 | help="""\ |
160 | @@ -123,8 +145,7 @@ | |||
161 | 123 | 145 | ||
162 | 124 | Possible values: | 146 | Possible values: |
163 | 125 | * none: Certificates ignored | 147 | * none: Certificates ignored |
166 | 126 | * optional: Certificates not required, but validated if provided | 148 | * required: Certificates required and validated |
165 | 127 | * required: Certificates required, and validated | ||
167 | 128 | """) | 149 | """) |
168 | 129 | 150 | ||
169 | 130 | checked_kerberos = False | 151 | checked_kerberos = False |
170 | @@ -448,34 +469,34 @@ | |||
171 | 448 | def connect_to_origin(self): | 469 | def connect_to_origin(self): |
172 | 449 | # FIXME JRV 2011-12-18: Use location config here? | 470 | # FIXME JRV 2011-12-18: Use location config here? |
173 | 450 | config_stack = config.GlobalStack() | 471 | config_stack = config.GlobalStack() |
174 | 451 | if self.ca_certs is None: | ||
175 | 452 | ca_certs = config_stack.get('ssl.ca_certs') | ||
176 | 453 | else: | ||
177 | 454 | ca_certs = self.ca_certs | ||
178 | 455 | cert_reqs = config_stack.get('ssl.cert_reqs') | 472 | cert_reqs = config_stack.get('ssl.cert_reqs') |
179 | 456 | if cert_reqs == ssl.CERT_NONE: | 473 | if cert_reqs == ssl.CERT_NONE: |
181 | 457 | trace.warning("not checking SSL certificates for %s: %d", | 474 | trace.warning("Not checking SSL certificate for %s: %d", |
182 | 458 | self.host, self.port) | 475 | self.host, self.port) |
183 | 476 | ca_certs = None | ||
184 | 459 | else: | 477 | else: |
185 | 478 | if self.ca_certs is None: | ||
186 | 479 | ca_certs = config_stack.get('ssl.ca_certs') | ||
187 | 480 | else: | ||
188 | 481 | ca_certs = self.ca_certs | ||
189 | 460 | if ca_certs is None: | 482 | if ca_certs is None: |
190 | 461 | trace.warning( | 483 | trace.warning( |
192 | 462 | "no valid trusted SSL CA certificates file set. See " | 484 | "No valid trusted SSL CA certificates file set. See " |
193 | 463 | "'bzr help ssl.ca_certs' for more information on setting " | 485 | "'bzr help ssl.ca_certs' for more information on setting " |
195 | 464 | "trusted CA's.") | 486 | "trusted CAs.") |
196 | 465 | try: | 487 | try: |
197 | 466 | ssl_sock = ssl.wrap_socket(self.sock, self.key_file, self.cert_file, | 488 | ssl_sock = ssl.wrap_socket(self.sock, self.key_file, self.cert_file, |
198 | 467 | cert_reqs=cert_reqs, ca_certs=ca_certs) | 489 | cert_reqs=cert_reqs, ca_certs=ca_certs) |
199 | 468 | except ssl.SSLError, e: | 490 | except ssl.SSLError, e: |
200 | 469 | if e.errno != ssl.SSL_ERROR_SSL: | ||
201 | 470 | raise | ||
202 | 471 | trace.note( | 491 | trace.note( |
206 | 472 | "To disable SSL certificate verification, use " | 492 | "\n" |
207 | 473 | "-Ossl.cert_reqs=none. See ``bzr help ssl.ca_certs`` for " | 493 | "See `bzr help ssl.ca_certs` for how to specify trusted CA" |
208 | 474 | "more information on specifying trusted CA certificates.") | 494 | "certificates.\n" |
209 | 495 | "Pass -Ossl.cert_reqs=none to disable certificate " | ||
210 | 496 | "verification entirely.\n") | ||
211 | 475 | raise | 497 | raise |
215 | 476 | peer_cert = ssl_sock.getpeercert() | 498 | if cert_reqs == ssl.CERT_REQUIRED: |
216 | 477 | if (cert_reqs == ssl.CERT_REQUIRED or | 499 | peer_cert = ssl_sock.getpeercert() |
214 | 478 | (cert_reqs == ssl.CERT_OPTIONAL and peer_cert)): | ||
217 | 479 | match_hostname(peer_cert, self.host) | 500 | match_hostname(peer_cert, self.host) |
218 | 480 | 501 | ||
219 | 481 | # Wrap the ssl socket before anybody use it | 502 | # Wrap the ssl socket before anybody use it |
220 | 482 | 503 | ||
221 | === modified file 'doc/en/release-notes/bzr-2.5.txt' | |||
222 | --- doc/en/release-notes/bzr-2.5.txt 2012-01-31 15:43:17 +0000 | |||
223 | +++ doc/en/release-notes/bzr-2.5.txt 2012-01-31 17:04:31 +0000 | |||
224 | @@ -56,12 +56,19 @@ | |||
225 | 56 | * ``bzr branch`` now fetches revisions when branching into an empty | 56 | * ``bzr branch`` now fetches revisions when branching into an empty |
226 | 57 | control directory. (Jelmer Vernooij, #905594) | 57 | control directory. (Jelmer Vernooij, #905594) |
227 | 58 | 58 | ||
228 | 59 | <<<<<<< TREE | ||
229 | 59 | * ``bzr branch`` generates correct target branch locations again if not | 60 | * ``bzr branch`` generates correct target branch locations again if not |
230 | 60 | specified. (Jelmer Vernooij, #919218) | 61 | specified. (Jelmer Vernooij, #919218) |
231 | 61 | 62 | ||
232 | 62 | * ``bzr send`` works on treeless branches again. | 63 | * ``bzr send`` works on treeless branches again. |
233 | 63 | (Jelmer Vernooij, #921591) | 64 | (Jelmer Vernooij, #921591) |
234 | 64 | 65 | ||
235 | 66 | ======= | ||
236 | 67 | * A sane default is provided for ``ssl.ca_certs`` which should points to the | ||
237 | 68 | Certificate Authority bundle for supported platforms. | ||
238 | 69 | (Vincent Ladeuil, #920455) | ||
239 | 70 | |||
240 | 71 | >>>>>>> MERGE-SOURCE | ||
241 | 65 | * Support scripts that don't call bzrlib.initialize() but still call run_bzr(). | 72 | * Support scripts that don't call bzrlib.initialize() but still call run_bzr(). |
242 | 66 | (Vincent Ladeuil, #917733) | 73 | (Vincent Ladeuil, #917733) |
243 | 67 | 74 |
@gz, Gordon: Feedback on where you expect to install the bundled ca certs expected ;)