title: Comparing two public keys with OpenSSL API
body: <p>I'm looking for a way to compare two public keys using the OpenSSL API in C++.  Of course, the most obvious way would be to serialize both keys into some format like PEM or DER, and then just compare the two serialized buffers.</p>
  
  <p>But I'm wondering if there is a more efficient way to compare the two keys that directly uses the OpenSSL key structures in memory.  Obviously, doing this would probably require different logic depending on what algorithm was used to generate the public key (along with its private counterpart.)</p>
  
  <p>So, to start out with something simple, suppose we only initially care about comparing RSA keys.  Since the <a href="https://en.wikipedia.org/wiki/RSA_(cryptosystem)#Key_generation" rel="nofollow noreferrer">public component of an RSA key</a> is the modulus <code>n</code> and the public exponent <code>e</code>, it seems we could just try to get those two numbers from each key and just compare them directly.  If they are equal, we can say the two public keys are equal.  </p>
  
  <p>The OpenSSL API provides a function to get these values, <a href="https://www.openssl.org/docs/man1.1.0/crypto/RSA_get0_key.html" rel="nofollow noreferrer"><code>RSA_get0_key</code></a>, which returns pointers to the internal <code>BIGNUM</code> objects <code>n</code>, <code>e</code>, and <code>d</code>, stored in the <code>RSA</code> struct.  We could then use <code>BN_cmp</code> to compare these objects directly.  So the C++ code would be something like:</p>
  
  <pre><code>bool compare_pubkeys(const EVP_PKEY* k1, const EVP_PKEY* k2)
  {
      // make sure both keys are the same type
      const int tp1 = EVP_PKEY_type(k1-&gt;type);
      const int tp2 = EVP_PKEY_type(k2-&gt;type);
      if (tp1 != tp2) return false;
  
      if (tp1 == EVP_PKEY_RSA) {
          RSA* rsa1 = EVP_PKEY_get1_RSA(k1);
          RSA* rsa2 = EVP_PKEY_get1_RSA(k2);
  
          const BIGNUM* n1;
          const BIGNUM* e1;
          const BIGNUM* n2;
          const BIGNUM* e2;
          RSA_get0_key(rsa1, &amp;n1, &amp;e1, nullptr);
          RSA_get0_key(rsa2, &amp;n2, &amp;e2, nullptr);
          const bool result = BN_cmp(n1, n2) == 0 &amp;&amp; BN_cmp(e1, e2) == 0;
  
          RSA_free(rsa1);
          RSA_free(rsa2);
          return result;
      }
      else { /* handle non-RSA keys later */ }
  
      return false;
  }
  </code></pre>
  
  <p><strong>My question</strong>: does this approach make sense?  I'm not by any means an expert in cryptography and I have an extremely basic understanding of how RSA keys work, so I don't know if there is something wrong with my approach.  My understanding is that given two RSA key pairs, comparing each <code>n</code> and <code>e</code> would be conceptually equivalent to checking if the two public keys were the same - but again, I'm not an expert so I am unsure if this is correct.</p>
  
  <p>So, is my approach here correct?</p>