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 
PoloChallengeResponse(X509 * client_cert,X509 * server_cert)26 PoloChallengeResponse::PoloChallengeResponse(X509* client_cert,
27                                              X509* server_cert)
28     : client_cert(client_cert),
29       server_cert(server_cert) {
30 }
31 
GetAlpha(const Nonce & nonce) const32 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 
GetGamma(const Nonce & nonce) const96 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 
ExtractNonce(const Gamma & gamma) const113 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 
CheckGamma(const Gamma & gamma) const124 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