Home | History | Annotate | Download | only in pairing
      1 // Copyright 2012 Google Inc. All Rights Reserved.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //     http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 // This class performs several computations on the client and server public keys
     16 // to generate and verify challenge hashes.
     17 
     18 #include "polo/pairing/polochallengeresponse.h"
     19 
     20 #include <glog/logging.h>
     21 #include "polo/util/poloutil.h"
     22 
     23 namespace polo {
     24 namespace pairing {
     25 
     26 PoloChallengeResponse::PoloChallengeResponse(X509* client_cert,
     27                                              X509* server_cert)
     28     : client_cert(client_cert),
     29       server_cert(server_cert) {
     30 }
     31 
     32 Alpha* PoloChallengeResponse::GetAlpha(const Nonce& nonce) const {
     33   EVP_PKEY* client_pkey = X509_get_pubkey(client_cert);
     34   if (!client_pkey) {
     35     return NULL;
     36   }
     37 
     38   RSA* client_pub_rsa = EVP_PKEY_get1_RSA(client_pkey);
     39   if (!client_pub_rsa) {
     40     return NULL;
     41   }
     42 
     43   EVP_PKEY* server_pkey = X509_get_pubkey(server_cert);
     44   if (!server_pkey) {
     45     return NULL;
     46   }
     47 
     48   RSA* server_pub_rsa = EVP_PKEY_get1_RSA(server_pkey);
     49   if (!server_pub_rsa) {
     50     return NULL;
     51   }
     52 
     53   // Compute a hash of the concatenated public keys. The client and server
     54   // modulus and exponent are concatenated along with the random nonce then a
     55   // SHA256 hash is computed on the result.
     56   size_t client_modulus_size = BN_num_bytes(client_pub_rsa->n);
     57   size_t client_exponent_size = BN_num_bytes(client_pub_rsa->e);
     58 
     59   size_t server_modulus_size = BN_num_bytes(server_pub_rsa->n);
     60   size_t server_exponent_size = BN_num_bytes(server_pub_rsa->e);
     61 
     62   size_t buffer_size = client_modulus_size + client_exponent_size
     63             + server_modulus_size + server_exponent_size
     64             + nonce.size();
     65 
     66   uint8_t* buffer = new unsigned char[buffer_size];
     67   uint8_t* pos = buffer;
     68 
     69   BN_bn2bin(client_pub_rsa->n, pos);
     70   pos += client_modulus_size;
     71 
     72   BN_bn2bin(client_pub_rsa->e, pos);
     73   pos += client_exponent_size;
     74 
     75   BN_bn2bin(server_pub_rsa->n, pos);
     76   pos += server_modulus_size;
     77 
     78   BN_bn2bin(server_pub_rsa->e, pos);
     79   pos += server_exponent_size;
     80 
     81   memcpy(pos, &nonce[0], nonce.size());
     82 
     83   Alpha* alpha = new Alpha(SHA256_DIGEST_LENGTH);
     84   SHA256(buffer, buffer_size, &(*alpha)[0]);
     85   delete[] buffer;
     86 
     87   RSA_free(client_pub_rsa);
     88   EVP_PKEY_free(client_pkey);
     89 
     90   RSA_free(server_pub_rsa);
     91   EVP_PKEY_free(server_pkey);
     92 
     93   return alpha;
     94 }
     95 
     96 Gamma* PoloChallengeResponse::GetGamma(const Nonce& nonce) const {
     97   const Alpha* alpha = GetAlpha(nonce);
     98   if (!alpha) {
     99     return NULL;
    100   }
    101 
    102   Gamma* gamma = new Gamma(nonce.size() * 2);
    103 
    104   if (alpha->size() >= nonce.size()) {
    105     memcpy(&(*gamma)[0], &(*alpha)[0], nonce.size());
    106     memcpy(&(*gamma)[nonce.size()], &nonce[0], nonce.size());
    107   }
    108   delete alpha;
    109 
    110   return gamma;
    111 }
    112 
    113 Nonce* PoloChallengeResponse::ExtractNonce(const Gamma& gamma) const {
    114   if ((gamma.size() < 2) || (gamma.size() % 2 != 0)) {
    115     return NULL;
    116   }
    117 
    118   Nonce* nonce = new Nonce(gamma.size() / 2);
    119   memcpy(&(*nonce)[0], &gamma[nonce->size()], nonce->size());
    120 
    121   return nonce;
    122 }
    123 
    124 bool PoloChallengeResponse::CheckGamma(const Gamma& gamma) const {
    125   const Nonce* nonce = ExtractNonce(gamma);
    126 
    127   if (!nonce) {
    128     return false;
    129   }
    130 
    131   const Gamma* expected = GetGamma(*nonce);
    132 
    133   LOG(INFO) << "CheckGamma expected: "
    134       << util::PoloUtil::BytesToHexString(&(*expected)[0], expected->size())
    135       << " actual: "
    136       << util::PoloUtil::BytesToHexString(&gamma[0], gamma.size());
    137 
    138   bool check = (gamma == (*expected));
    139 
    140   delete nonce;
    141   delete expected;
    142 
    143   return check;
    144 }
    145 
    146 }  // namespace pairing
    147 }  // namespace polo
    148