title: Extract Public Key using pyOpenSSL from certificate or other connection information
body: <p>I'm currently trying to write a python server script which should authenticate the current client based on its public key. Since I'm using twisted, the <a href="http://twistedmatrix.com/documents/11.0.0/core/howto/ssl.html#auto7" rel="nofollow noreferrer">example in the twisted documenteation</a> got me started.</p>
  <p>While I can generate keys, connect and communicate using the example code, I have not yet found a way to get the public key of the client in a usable format. In <a href="https://stackoverflow.com/questions/10362965/how-to-get-public-key-using-pyopenssl">this stackexchange question</a> somebody extracts the public key from an <code>OpenSSL.crypto.PKey</code> object but cannot transform it to a readable format. Since in I have access to the <code>PKey</code> object of the x509 certificate in the <code>verifyCallback</code> method or via <code>self.transport.getPeerCertificate()</code> from any method of my Protocol, this would be a good way to go. The (not accepted) answer suggests to try <code>crypto.dump_privatekey(PKey)</code>. Unfortunately, this does not really yield the expected result:
  While the <code>BEGIN PRIVATE KEY</code> and <code>BEGIN PRIVATE KEY</code> in the answer could be fixed by an easy text replacement function, the base64 string seems not match the public key. I've extracted the public key with <code>openssl rsa -in client.key -pubout &gt; client.pub</code> as mentioned <a href="https://stackoverflow.com/questions/10271197/openssl-how-to-extract-public-key">here</a>. It does not match the result of the <code>dump_privatekey</code> function.</p>
  <p>While there still is an <a href="https://bugs.launchpad.net/pyopenssl/+bug/780089" rel="nofollow noreferrer">open bug towards OpenSSL on launchpad</a>, it is not yet fixed. It was reported 19 Month ago, and there is some recent (October 2012) activity on it, I do not have any hope of a fast fix in the repos.</p>
  <p>Do you have any other ideas how I could get the public key in a format comparable to the <code>client.pub</code> file I have mentioned above? Perhaps there is a twisted or OpenSSL connection specific object which holds this information. Please note that I have to store the public key in the protocol object such that I can access it later.</p>
  <h2>Why is no Answer accepted?</h2>
  <h3>M2Crypto by J.F. Sebastian</h3>
  <p>Sorry, that I had not thought of a possibility where I cannot correlate the certificate to the connection. I've added the requirement that I have to store the public key inside the protocol instance. Thus, using <code>peerX509.as_pem()</code> inside the <code>postConnectionCheck</code> function as suggested by J.F. Sebastian does not work. Furthermore, at least in version 0.21.1-2ubuntu3 of python-m2crypto I have to call <code>peerX509.get_rsa().as_pem()</code> to get the right public key. Using <code>peerX509.as_pem(None)</code> (since <code>peerX509.as_pem()</code> still wants a passphrase) yields excactly the same output as <code>crypto.dump_privatekey(PKey)</code> in PyOpenSSL. Maybe there is a bug.</p>
  <p>Besides this, the answer showed me a possible way to write another workaround by using the following <code>Echo</code> protocol class:</p>
  <pre><code>class Echo(Protocol):
      def dataReceived(self, data):
          &quot;&quot;&quot;As soon as any data is received, write it back.&quot;&quot;&quot;
          if self.transport.checked and not self.pubkeyStored:
              self.pubkeyStored = True
              x509 = m2.ssl_get_peer_cert(self.transport.ssl._ptr())
              if x509 is not None:
                  x509 = X509.X509(x509, 1)
                  pk = x509.get_pubkey()
                  self.pubkey = pk.get_rsa().as_pem()
                  print pk.as_pem(None)
              print self.pubkey
          self.transport.write(data)
  </code></pre>
  <p>As you can see this uses some internal classes which I'd like to prevent. I'm hesitating submitting a small patch which would add a <code>getCert</code> method to the <code>TLSProtocolWrapper</code> class in M2Crypto.SSL.TwistedProtocolWrapper. Even if it was accepted upstream, it would break compatibility of my script with any but the most cut-of-the-edge versions of m2crypto. What would you do?</p>
  <h3>External OpenSSL call by me</h3>
  <p>Well, its an ugly workaround based on external system commands just which seems to me even worse than accessing non-public attributes.</p>