
Can someone help me fill in the blanks here? I've got an AMP connection up and running, I just want to: 1) Make it so that AMP uses an SSL connection (which appears to be supported by AMP with StartTLS) -- I'm confident that it's only a matter of a little bit more time and experimentation for me to get this part working. 2) Make it so that both the client and the server only connect to each other and no one else. I'm fairly certain this has something to do with making my own certificate authority and certificates. I (with Google's help) am capable of figuring out all the OpenSSL commands to do the creating, signing, etc. of certificates, but I'm not sure what exactly needs to be done. Any pointers would be appreciated... * Here's the docs I've found so far for twisted+ssl+amp: (There's a StartTLS in AMP, ) http://twistedmatrix.com/documents/current/api/twisted.protocols.amp.html http://twistedmatrix.com/documents/current/api/twisted.protocols.amp.StartTL... (There's an ssl in twisted.internet) http://twistedmatrix.com/documents/current/api/twisted.internet.ssl.html (The SSL examples use a ClientContextFactory...which is undocumented) http://twistedmatrix.com/projects/core/documentation/examples/echoserv_ssl.p... http://twistedmatrix.com/projects/core/documentation/examples/echoclient_ssl... http://twistedmatrix.com/documents/current/api/twisted.internet.ssl.ClientCo...

On 18 Mar, 10:34 pm, nathan.stocks@gmail.com wrote:
AMP already supports this, so you don't have anything to do...
And this is really just learning about the OpenSSL APIs.
Any pointers would be appreciated...
I would definitely look at the API docs for twisted.internet.ssl. You don't even need to use openssl to generate and sign certificates (although currently some functionality is missing). If you could give some explanation of the security properties you expect (how do you intend for the client and server to exchange information about who they "really" are?) then we might be able to offer more direct guidance.

On Wed, Mar 19, 2008 at 3:09 PM, <glyph@divmod.com> wrote:
The security properties that I want are: 1) My client and my server refuse to establish SSL (or any other type of) connections with anybody but each other. 2) My client and server do establish SSL connections with each other. Pretty simple in concept, really. I'll go read the API docs like you suggested... ~ Nathan

On Wed, 19 Mar 2008 20:14:09 -0600 Nathan <nathan.stocks@gmail.com> wrote:
For reference, this is almost exactly what Foolscap does. The server registers an object and gets back a "FURL" which contains two cryptographic values: the hash of the SSL certificate, and the per-object secret. You give this FURL to the client by some out-of-band means (paste it into a config file, perhaps). Then the client connects to the server over SSL, verifies the certificate hash, sends the secret, and gets back a reference to the object. The client will refuse to use any connection that has a different SSL certificate. It will also refuse to use a non-SSL connection. The part where the capability-oriented Foolscap model differs from your stated properties is that the server makes no attempt to distinguish between various clients. Any client which knows the FURL will be granted access to the object that you've registered. To accomplish both of your goals, simply don't reveal the FURL to anyone but your desired client. Unauthorized clients will be able to make an SSL connection to the server but they won't know the object secret and will be unable to access the object. If you use Foolscap, you'll be working with objects and remote method calls, rather than the single-endpoint model that AMP uses. This may be more flexibility than you really need, but if you only publish one object and always call a single method (perhaps called 'dispatch'), then you can program in the same style. Of course, when you want to use multiple objects, pass arbitrary reference graphs in arguments and responses, or allow third-party introductions, Foolscap will be ready for you :). http://foolscap.lothar.com/trac cheers, -Brian

On Thu, Mar 20, 2008 at 3:45 PM, Brian Warner <warner@lothar.com> wrote:
Now that foolscap has been brought up ... since foolscap doesn't try to poke through firewalls, there seems to be some deployment issues when using this in say an MMO where you can't guarantee that participants in the system will be able talk to each other directly without tunneling through a central server. The way foolscap works (if I understand correctly), a server A can introduce a client B to C by passing B the FURL to some object hosted in B's tub. Is it sane the best way to handle the scenario when B and C can't establish a connection to each other (one or both are behind a NAT), but both trust A to make a proxy reference to the other on the server and simply route the conversation. Does foolscap already support such fall-back behavior for coping with firewalls? Or does that break the security model? -- \\\\\/\"/\\\\\\\\\\\ \\\\/ // //\/\\\\\\\ \\\/ \\// /\ \/\\\\ \\/ /\/ / /\/ /\ \\\ \/ / /\/ /\ /\\\ \\ / /\\\ /\\\ \\\\\/\ \/\\\\\/\\\\\/\\\\\\ d.p.s

On Thu, Mar 20, 2008 at 4:38 PM, Drew Smathers <drew.smathers@gmail.com> wrote:
Woops, correction: "server A can introduce a client B to C by passing B the FURL to some object hosted in C's tub" -- \\\\\/\"/\\\\\\\\\\\ \\\\/ // //\/\\\\\\\ \\\/ \\// /\ \/\\\\ \\/ /\/ / /\/ /\ \\\ \/ / /\/ /\ /\\\ \\ / /\\\ /\\\ \\\\\/\ \/\\\\\/\\\\\/\\\\\\ d.p.s

Does foolscap already support such fall-back behavior for coping with firewalls? Or does that break the security model?
Not yet, and yes.
"server A can introduce a client B to C by passing B the FURL to some object hosted in C's tub"
A motivating use case would be a chat system, in which the central server was used to introduce clients to each other, and all messages were sent directly from one client to another. B and C might be two separate clients, and the point of introduction is when B wants to connect to C. The server can stash a reference to an object in C's tub, or a FURL to that object that was generated by C. It can then send one of these to B (perhaps as an argument to publish message, or a response to a "get all connected clients" request message). The gift/introduction code in Foolscap lets you send live references (i.e. RemoteReference instances) to third parties, and in the current release this causes the FURL of the target to be delivered and automatically connected to. But of course this requires that the recipient of the gift be able to connect to the target, and if that target is behind a firewall then the introduction will fail. We don't have any sort of relay or hole-punching code in place yet. As a result, in Tahoe (http://allmydata.org), the few places that use Introduction are careful to arrange for the target of the introduction (the "gift") to be on the publically-visible server, rather than on the probably-behind-NAT client. Possible solutions: 1: non-Membrane plaintext Forwarder It is pretty easy to build a server-side proxy (called a Forwarder) that has a doRemoteCall() method that just echoes the request on to another object. Each time B sends a message to that-which-they-think-is-C, really they're sending it to a Forwarder on A, and the Forwarder sends the request on to C, gets the response, and forwards the response back to B. This takes about 5 lines of code: class Forwarder(Referenceable): def __init__(self, target): self.target = target def doRemoteCall(self, methname, args, kwargs): return self.target.callRemote(methname, *args, **kwargs) The first disadvantage is that the Forwarder gets to see (and control) all messages, so you're vulnerable to it for confidentiality and integrity. The second disadvantage is that if there are other object references in the arguments or the responses, those need to be wrapped in Forwarders too. This is a job for the "Membrane" pattern. 2: yes-Membrane plaintext Forwarder Eventually Foolscap will have utility functions for building easy membranes, but not yet. (foolscap ticket #44). Having this would remove the prohibitions on putting object references in your arguments and return values, but doesn't remove the vulnerability to the forwarder. 3: per-message ciphertext proxy Like the Forwarder, but you change the client to encrypt all its messages first, and the server to decrypt them. This keeps the proxy from seeing the contents of the messages. Encrypt the responses too. Add more crypto goo to make sure the proxy can't corrupt either. Foolscap has some support for serializing arbitrary object graphs, which would help. The "Sealer/Unsealer" code (foolscap ticket #20) that is under development will handle both the serialization and the encryption. You'd need some extra layer to figure out what keys to use. 4: server-side per-Tub ciphertext proxy The Foolscap negotiation protocol is specifically designed to provide for multiple Tubs listening on the same port. We build a Relay process to which the NAT-bound Tubs can attach, registering themselves with a (tubid, listener_rref) tuple. This listener_rref object has a single accept() method, which returns a handler_rref object. When B wants to connect to C, the FURL it uses will contain C's tubid but will have connection hints that point to the relay's listening socket. When B connects to the relay and says it wants to talk to tubidC, the relay (during the negotiation process) tells the listener_rref that it wants a new connection, gets the handler_rref, then switches into a simple proxy mode where it copies data from the B-side connection into remote_write() messages sent to the handler_rref. On C, the contents of these messages are written into a loopback TCP socket that mimics the data being exchanged between B and the relay. Responses generated by C get proxied backwards to the relay over the same connection. This requires more code, but it's the "right way to do it" for relay. The intermediate relay doesn't get to see or corrupt the traffic that it is carrying, and the remote objects on B and C don't need to be aware that anything unusual is going on. C needs to register with the relay, and the FURL needs to be created with the right connection hints, but that can be done once at startup (instead of requiring that every single message be specially encrypted). This one is tracked with foolscap ticket #46, copied directly from this note. cheers, -Brian

Nathan <nathan.stocks@gmail.com> writes:
I posted a while back a small sample of how to handle that for a general Twisted protocol that might be of some help, or point you in the right direction as well. http://twistedmatrix.com/pipermail/twisted-python/2007-August/015935.html (Note the followup messages that clarify an erroneous "False" left in the original posted code) This works fine with just normal CA/server/client certificates created through the standard OpenSSL process and tools. -- David

On Fri, Mar 21, 2008 at 2:56 PM, David Bolen <db3l.net@gmail.com> wrote:
That's just what I was looking for! I'm going to see if I can use that example to add SSL to my AMP stuff by the end of today. First, I've got to finish figuring out the certificate authority stuff. I'm working through the following page to set up my own local CA: http://sial.org/howto/openssl/ca/ If anyone knows a better guide to follow, please let me know! ~ Nathan ~ Nathan

On Fri, Mar 21, 2008 at 2:56 PM, David Bolen <db3l.net@gmail.com> wrote:
I've generated a CA file, some private keys (and their corresponding CSR's and certificates), and incorporated chunks of code from the post you linked to above (and fixed the "returning ok" bit), but I'm running into the following error: [('SSL routines', 'SSL3_READ_BYTES', 'sslv3 alert certificate unknown'), ('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')] So close! I wonder if this has something to do with the fact that my two endpoints are both on localhost, and not on some domain name? Just a stab in the dark. Anyway, here's the debugging print statement info from the client side (I scrubbed out personal info): _verify (ok=1): subject: <X509Name object '/CN=MyCompany CA/C=US/ST=Utah/L=MyCity/O=mycompany.com/emailAddress=operations@mycompany.com'> issuer: <X509Name object '/CN=MyCompany CA/C=US/ST=Utah/L=MyCity/O=mycompany.com/emailAddress=operations@mycompany.com'> errnum 0, errdepth 1 _verify (ok=1): subject: <X509Name object '/C=US/ST=Utah/O=mycompany.com/CN=controller/emailAddress=operations@mycompany.com'> issuer: <X509Name object '/CN=MyCompany CA/C=US/ST=Utah/L=MyCity/O=mycompany.com/emailAddress=operations@mycompany.com'> errnum 0, errdepth 0 And here's the ssl code from the client (the only significant change I made was the filenames): class ClientContextFactory(ssl.ClientContextFactory): def _verify(self, connection, x509, errnum, errdepth, ok): print '_verify (ok=%d):' % ok print ' subject:', x509.get_subject() print ' issuer:', x509.get_issuer() print ' errnum %s, errdepth %d' % (errnum, errdepth) return ok def getContext(self): ctx = ssl.ClientContextFactory.getContext(self) ctx.use_certificate_file('ssl/private/nathanmonitor.cert') ctx.use_privatekey_file('ssl/private/nathanmonitor.key') ctx.load_verify_locations('ssl/ca-cert.pem') ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, self._verify) return ctx ClientCreator(reactor, MonitorClientProtocol).connectSSL( 'localhost', MONITOR_PORT, ClientContextFactory()).addCallback( monitor_window.install_amp_client) nathanmonitor.key is the private ssl key of my "monitor" client ca-cert.pem is the custom CA certificate I made by following http://sial.org/howto/openssl/ca/ nathanmonitor.cert is the ssl certificate of my "monitor" client generated with my custom CA and a .csr of nathanmonitor.key On the server side, the error output is pretty quiet: _verify (ok=1): subject:<X509Name object '/CN=MyCompany CA/C=US/ST=Utah/L=MyCity/O=mycompany.com/emailAddress=operations@mycompany.com'> ...here's my server code (again, pretty much the same except for cert files) class ServerContextFactory: def _verify(self, connection, x509, errnum, errdepth, ok): logging.info('_verify (ok=%d):' % ok) logging.info(' subject:%s' % x509.get_subject()) logging.info(' issuer:', x509.get_issuer()) logging.info(' errnum %s, errdepth %d' % (errnum, errdepth)) return ok def getContext(self): """Create an SSL context.""" ctx = SSL.Context(SSL.SSLv23_METHOD) ctx.use_certificate_file('ssl/private/controller.cert') ctx.use_privatekey_file('ssl/private/controller.key') ctx.load_client_ca('ssl/ca-cert.pem') ctx.load_verify_locations('ssl/ca-cert.pem') ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, self._verify) ctx.set_verify_depth(10) return ctx reactor.listenSSL(MONITOR_PORT, monitor_factory, ServerContextFactory()) controller.key is the private ssl key of the "server" ca-cert.pem is the same custom CA certificate file as used in the client. controller.cert is the ssl certificate of the "server" generated with my custom CA and a .csr of controller.key

I'm not concious of changing anything, but the error has changed to simply: [('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')] ...and none of the _verify() debugging output is being printed out on either side anymore. Weird! ~ Nathan

On Mon, Mar 24, 2008 at 2:57 PM, Nathan <nathan.stocks@gmail.com> wrote:
Ooops, ignore this last email. I found that I had routed stderr away, and wasn't seeing a crash caused by a typo I introduced after (almost) getting the ssl to work. So it's back to the first error now: [('SSL routines', 'SSL3_READ_BYTES', 'sslv3 alert certificate unknown'), ('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')] ~ Nathan

On Mon, Mar 24, 2008 at 3:07 PM, Nathan <nathan.stocks@gmail.com> wrote:
It works! After finding that I had lost track of stderr, I found that the ssl error had an error on this line: logging.info(' issuer:', x509.get_issuer()) which ought to be: logging.info(' issuer:%s' % x509.get_issuer()) Thanks for all the help! It looks like my AMP+SSL connection is up and running! ~ Nathan

On 18 Mar, 10:34 pm, nathan.stocks@gmail.com wrote:
AMP already supports this, so you don't have anything to do...
And this is really just learning about the OpenSSL APIs.
Any pointers would be appreciated...
I would definitely look at the API docs for twisted.internet.ssl. You don't even need to use openssl to generate and sign certificates (although currently some functionality is missing). If you could give some explanation of the security properties you expect (how do you intend for the client and server to exchange information about who they "really" are?) then we might be able to offer more direct guidance.

On Wed, Mar 19, 2008 at 3:09 PM, <glyph@divmod.com> wrote:
The security properties that I want are: 1) My client and my server refuse to establish SSL (or any other type of) connections with anybody but each other. 2) My client and server do establish SSL connections with each other. Pretty simple in concept, really. I'll go read the API docs like you suggested... ~ Nathan

On Wed, 19 Mar 2008 20:14:09 -0600 Nathan <nathan.stocks@gmail.com> wrote:
For reference, this is almost exactly what Foolscap does. The server registers an object and gets back a "FURL" which contains two cryptographic values: the hash of the SSL certificate, and the per-object secret. You give this FURL to the client by some out-of-band means (paste it into a config file, perhaps). Then the client connects to the server over SSL, verifies the certificate hash, sends the secret, and gets back a reference to the object. The client will refuse to use any connection that has a different SSL certificate. It will also refuse to use a non-SSL connection. The part where the capability-oriented Foolscap model differs from your stated properties is that the server makes no attempt to distinguish between various clients. Any client which knows the FURL will be granted access to the object that you've registered. To accomplish both of your goals, simply don't reveal the FURL to anyone but your desired client. Unauthorized clients will be able to make an SSL connection to the server but they won't know the object secret and will be unable to access the object. If you use Foolscap, you'll be working with objects and remote method calls, rather than the single-endpoint model that AMP uses. This may be more flexibility than you really need, but if you only publish one object and always call a single method (perhaps called 'dispatch'), then you can program in the same style. Of course, when you want to use multiple objects, pass arbitrary reference graphs in arguments and responses, or allow third-party introductions, Foolscap will be ready for you :). http://foolscap.lothar.com/trac cheers, -Brian

On Thu, Mar 20, 2008 at 3:45 PM, Brian Warner <warner@lothar.com> wrote:
Now that foolscap has been brought up ... since foolscap doesn't try to poke through firewalls, there seems to be some deployment issues when using this in say an MMO where you can't guarantee that participants in the system will be able talk to each other directly without tunneling through a central server. The way foolscap works (if I understand correctly), a server A can introduce a client B to C by passing B the FURL to some object hosted in B's tub. Is it sane the best way to handle the scenario when B and C can't establish a connection to each other (one or both are behind a NAT), but both trust A to make a proxy reference to the other on the server and simply route the conversation. Does foolscap already support such fall-back behavior for coping with firewalls? Or does that break the security model? -- \\\\\/\"/\\\\\\\\\\\ \\\\/ // //\/\\\\\\\ \\\/ \\// /\ \/\\\\ \\/ /\/ / /\/ /\ \\\ \/ / /\/ /\ /\\\ \\ / /\\\ /\\\ \\\\\/\ \/\\\\\/\\\\\/\\\\\\ d.p.s

On Thu, Mar 20, 2008 at 4:38 PM, Drew Smathers <drew.smathers@gmail.com> wrote:
Woops, correction: "server A can introduce a client B to C by passing B the FURL to some object hosted in C's tub" -- \\\\\/\"/\\\\\\\\\\\ \\\\/ // //\/\\\\\\\ \\\/ \\// /\ \/\\\\ \\/ /\/ / /\/ /\ \\\ \/ / /\/ /\ /\\\ \\ / /\\\ /\\\ \\\\\/\ \/\\\\\/\\\\\/\\\\\\ d.p.s

Does foolscap already support such fall-back behavior for coping with firewalls? Or does that break the security model?
Not yet, and yes.
"server A can introduce a client B to C by passing B the FURL to some object hosted in C's tub"
A motivating use case would be a chat system, in which the central server was used to introduce clients to each other, and all messages were sent directly from one client to another. B and C might be two separate clients, and the point of introduction is when B wants to connect to C. The server can stash a reference to an object in C's tub, or a FURL to that object that was generated by C. It can then send one of these to B (perhaps as an argument to publish message, or a response to a "get all connected clients" request message). The gift/introduction code in Foolscap lets you send live references (i.e. RemoteReference instances) to third parties, and in the current release this causes the FURL of the target to be delivered and automatically connected to. But of course this requires that the recipient of the gift be able to connect to the target, and if that target is behind a firewall then the introduction will fail. We don't have any sort of relay or hole-punching code in place yet. As a result, in Tahoe (http://allmydata.org), the few places that use Introduction are careful to arrange for the target of the introduction (the "gift") to be on the publically-visible server, rather than on the probably-behind-NAT client. Possible solutions: 1: non-Membrane plaintext Forwarder It is pretty easy to build a server-side proxy (called a Forwarder) that has a doRemoteCall() method that just echoes the request on to another object. Each time B sends a message to that-which-they-think-is-C, really they're sending it to a Forwarder on A, and the Forwarder sends the request on to C, gets the response, and forwards the response back to B. This takes about 5 lines of code: class Forwarder(Referenceable): def __init__(self, target): self.target = target def doRemoteCall(self, methname, args, kwargs): return self.target.callRemote(methname, *args, **kwargs) The first disadvantage is that the Forwarder gets to see (and control) all messages, so you're vulnerable to it for confidentiality and integrity. The second disadvantage is that if there are other object references in the arguments or the responses, those need to be wrapped in Forwarders too. This is a job for the "Membrane" pattern. 2: yes-Membrane plaintext Forwarder Eventually Foolscap will have utility functions for building easy membranes, but not yet. (foolscap ticket #44). Having this would remove the prohibitions on putting object references in your arguments and return values, but doesn't remove the vulnerability to the forwarder. 3: per-message ciphertext proxy Like the Forwarder, but you change the client to encrypt all its messages first, and the server to decrypt them. This keeps the proxy from seeing the contents of the messages. Encrypt the responses too. Add more crypto goo to make sure the proxy can't corrupt either. Foolscap has some support for serializing arbitrary object graphs, which would help. The "Sealer/Unsealer" code (foolscap ticket #20) that is under development will handle both the serialization and the encryption. You'd need some extra layer to figure out what keys to use. 4: server-side per-Tub ciphertext proxy The Foolscap negotiation protocol is specifically designed to provide for multiple Tubs listening on the same port. We build a Relay process to which the NAT-bound Tubs can attach, registering themselves with a (tubid, listener_rref) tuple. This listener_rref object has a single accept() method, which returns a handler_rref object. When B wants to connect to C, the FURL it uses will contain C's tubid but will have connection hints that point to the relay's listening socket. When B connects to the relay and says it wants to talk to tubidC, the relay (during the negotiation process) tells the listener_rref that it wants a new connection, gets the handler_rref, then switches into a simple proxy mode where it copies data from the B-side connection into remote_write() messages sent to the handler_rref. On C, the contents of these messages are written into a loopback TCP socket that mimics the data being exchanged between B and the relay. Responses generated by C get proxied backwards to the relay over the same connection. This requires more code, but it's the "right way to do it" for relay. The intermediate relay doesn't get to see or corrupt the traffic that it is carrying, and the remote objects on B and C don't need to be aware that anything unusual is going on. C needs to register with the relay, and the FURL needs to be created with the right connection hints, but that can be done once at startup (instead of requiring that every single message be specially encrypted). This one is tracked with foolscap ticket #46, copied directly from this note. cheers, -Brian

Nathan <nathan.stocks@gmail.com> writes:
I posted a while back a small sample of how to handle that for a general Twisted protocol that might be of some help, or point you in the right direction as well. http://twistedmatrix.com/pipermail/twisted-python/2007-August/015935.html (Note the followup messages that clarify an erroneous "False" left in the original posted code) This works fine with just normal CA/server/client certificates created through the standard OpenSSL process and tools. -- David

On Fri, Mar 21, 2008 at 2:56 PM, David Bolen <db3l.net@gmail.com> wrote:
That's just what I was looking for! I'm going to see if I can use that example to add SSL to my AMP stuff by the end of today. First, I've got to finish figuring out the certificate authority stuff. I'm working through the following page to set up my own local CA: http://sial.org/howto/openssl/ca/ If anyone knows a better guide to follow, please let me know! ~ Nathan ~ Nathan

On Fri, Mar 21, 2008 at 2:56 PM, David Bolen <db3l.net@gmail.com> wrote:
I've generated a CA file, some private keys (and their corresponding CSR's and certificates), and incorporated chunks of code from the post you linked to above (and fixed the "returning ok" bit), but I'm running into the following error: [('SSL routines', 'SSL3_READ_BYTES', 'sslv3 alert certificate unknown'), ('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')] So close! I wonder if this has something to do with the fact that my two endpoints are both on localhost, and not on some domain name? Just a stab in the dark. Anyway, here's the debugging print statement info from the client side (I scrubbed out personal info): _verify (ok=1): subject: <X509Name object '/CN=MyCompany CA/C=US/ST=Utah/L=MyCity/O=mycompany.com/emailAddress=operations@mycompany.com'> issuer: <X509Name object '/CN=MyCompany CA/C=US/ST=Utah/L=MyCity/O=mycompany.com/emailAddress=operations@mycompany.com'> errnum 0, errdepth 1 _verify (ok=1): subject: <X509Name object '/C=US/ST=Utah/O=mycompany.com/CN=controller/emailAddress=operations@mycompany.com'> issuer: <X509Name object '/CN=MyCompany CA/C=US/ST=Utah/L=MyCity/O=mycompany.com/emailAddress=operations@mycompany.com'> errnum 0, errdepth 0 And here's the ssl code from the client (the only significant change I made was the filenames): class ClientContextFactory(ssl.ClientContextFactory): def _verify(self, connection, x509, errnum, errdepth, ok): print '_verify (ok=%d):' % ok print ' subject:', x509.get_subject() print ' issuer:', x509.get_issuer() print ' errnum %s, errdepth %d' % (errnum, errdepth) return ok def getContext(self): ctx = ssl.ClientContextFactory.getContext(self) ctx.use_certificate_file('ssl/private/nathanmonitor.cert') ctx.use_privatekey_file('ssl/private/nathanmonitor.key') ctx.load_verify_locations('ssl/ca-cert.pem') ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, self._verify) return ctx ClientCreator(reactor, MonitorClientProtocol).connectSSL( 'localhost', MONITOR_PORT, ClientContextFactory()).addCallback( monitor_window.install_amp_client) nathanmonitor.key is the private ssl key of my "monitor" client ca-cert.pem is the custom CA certificate I made by following http://sial.org/howto/openssl/ca/ nathanmonitor.cert is the ssl certificate of my "monitor" client generated with my custom CA and a .csr of nathanmonitor.key On the server side, the error output is pretty quiet: _verify (ok=1): subject:<X509Name object '/CN=MyCompany CA/C=US/ST=Utah/L=MyCity/O=mycompany.com/emailAddress=operations@mycompany.com'> ...here's my server code (again, pretty much the same except for cert files) class ServerContextFactory: def _verify(self, connection, x509, errnum, errdepth, ok): logging.info('_verify (ok=%d):' % ok) logging.info(' subject:%s' % x509.get_subject()) logging.info(' issuer:', x509.get_issuer()) logging.info(' errnum %s, errdepth %d' % (errnum, errdepth)) return ok def getContext(self): """Create an SSL context.""" ctx = SSL.Context(SSL.SSLv23_METHOD) ctx.use_certificate_file('ssl/private/controller.cert') ctx.use_privatekey_file('ssl/private/controller.key') ctx.load_client_ca('ssl/ca-cert.pem') ctx.load_verify_locations('ssl/ca-cert.pem') ctx.set_verify(SSL.VERIFY_PEER|SSL.VERIFY_FAIL_IF_NO_PEER_CERT, self._verify) ctx.set_verify_depth(10) return ctx reactor.listenSSL(MONITOR_PORT, monitor_factory, ServerContextFactory()) controller.key is the private ssl key of the "server" ca-cert.pem is the same custom CA certificate file as used in the client. controller.cert is the ssl certificate of the "server" generated with my custom CA and a .csr of controller.key

I'm not concious of changing anything, but the error has changed to simply: [('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')] ...and none of the _verify() debugging output is being printed out on either side anymore. Weird! ~ Nathan

On Mon, Mar 24, 2008 at 2:57 PM, Nathan <nathan.stocks@gmail.com> wrote:
Ooops, ignore this last email. I found that I had routed stderr away, and wasn't seeing a crash caused by a typo I introduced after (almost) getting the ssl to work. So it's back to the first error now: [('SSL routines', 'SSL3_READ_BYTES', 'sslv3 alert certificate unknown'), ('SSL routines', 'SSL3_READ_BYTES', 'ssl handshake failure')] ~ Nathan

On Mon, Mar 24, 2008 at 3:07 PM, Nathan <nathan.stocks@gmail.com> wrote:
It works! After finding that I had lost track of stderr, I found that the ssl error had an error on this line: logging.info(' issuer:', x509.get_issuer()) which ought to be: logging.info(' issuer:%s' % x509.get_issuer()) Thanks for all the help! It looks like my AMP+SSL connection is up and running! ~ Nathan
participants (6)
-
Brian Warner
-
David Bolen
-
Drew Smathers
-
glyph@divmod.com
-
Nathan
-
Pavel Pergamenshchik