1 /*
2 * Copyright (C) 2021 Huawei Device Co., Ltd.
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 #include "auth.h"
16 #include <openssl/evp.h>
17 #include <openssl/objects.h>
18 #include <openssl/pem.h>
19 #include <openssl/rsa.h>
20 #include <openssl/sha.h>
21
22 using namespace Hdc;
23 #define BIGNUMTOBIT 32
24
25 namespace HdcAuth {
26 // ---------------------------------------Cheat compiler---------------------------------------------------------
27 #ifdef HDC_HOST
28
AuthVerify(uint8_t * token,uint8_t * sig,int siglen)29 bool AuthVerify(uint8_t *token, uint8_t *sig, int siglen)
30 {
31 return false;
32 };
PostUIConfirm(string publicKey)33 bool PostUIConfirm(string publicKey)
34 {
35 return false;
36 }
37
38 #else // daemon
39
40 bool GenerateKey(const char *file)
41 {
42 return false;
43 };
44 int AuthSign(void *rsa, const unsigned char *token, size_t tokenSize, void *sig)
45 {
46 return 0;
47 };
48 int GetPublicKeyFileBuf(unsigned char *data, size_t len)
49 {
50 return 0;
51 }
52
53 #endif
54 // ------------------------------------------------------------------------------------------------
55
56 const uint32_t RSANUMBYTES = 512; // 4096 bit key length
57 const uint32_t RSANUMWORDS = (RSANUMBYTES / sizeof(uint32_t));
58 struct RSAPublicKey {
59 int wordModulusSize; // Length of n[] in number of uint32_t */
60 uint32_t rsaN0inv; // -1 / n[0] mod 2^32
61 uint32_t modulus[RSANUMWORDS]; // modulus as little endian array
62 uint32_t rr[RSANUMWORDS]; // R^2 as little endian array
63 BN_ULONG exponent; // 3 or 65537
64 };
65
66 #ifdef HDC_HOST
67 // Convert OpenSSL RSA private key to pre-computed RSAPublicKey format
RSA2RSAPublicKey(RSA * rsa,RSAPublicKey * publicKey)68 int RSA2RSAPublicKey(RSA *rsa, RSAPublicKey *publicKey)
69 {
70 int result = 1;
71 unsigned int i;
72 BN_CTX *ctx = BN_CTX_new();
73 BIGNUM *r32 = BN_new();
74 BIGNUM *rsaRR = BN_new();
75 BIGNUM *rsaR = BN_new();
76 BIGNUM *rsaRem = BN_new();
77 BIGNUM *rsaN0inv = BN_new();
78 #ifdef OPENSSL_IS_BORINGSSL
79 // boringssl
80 BIGNUM *n = BN_new();
81 BN_copy(n, rsa->n);
82 publicKey->exponent = BN_get_word(rsa->e);
83 #else
84 // openssl
85 #if OPENSSL_VERSION_NUMBER >= 0x10100005L
86 BIGNUM *n = (BIGNUM *)RSA_get0_n(rsa);
87 publicKey->exponent = BN_get_word(RSA_get0_e(rsa));
88 #else
89 BIGNUM *n = BN_new();
90 BN_copy(n, rsa->n);
91 publicKey->exponent = BN_get_word(rsa->e);
92 #endif
93
94 #endif // OPENSSL_IS_BORINGSSL
95 while (true) {
96 if (RSA_size(rsa) != RSANUMBYTES) {
97 result = 0;
98 break;
99 }
100
101 BN_set_bit(r32, BIGNUMTOBIT);
102 BN_set_bit(rsaR, RSANUMWORDS * BIGNUMTOBIT);
103 BN_mod_sqr(rsaRR, rsaR, n, ctx);
104 BN_div(nullptr, rsaRem, n, r32, ctx);
105 BN_mod_inverse(rsaN0inv, rsaRem, r32, ctx);
106 publicKey->wordModulusSize = RSANUMWORDS;
107 publicKey->rsaN0inv = 0 - BN_get_word(rsaN0inv);
108 for (i = 0; i < RSANUMWORDS; ++i) {
109 BN_div(rsaRR, rsaRem, rsaRR, r32, ctx);
110 publicKey->rr[i] = BN_get_word(rsaRem);
111 BN_div(n, rsaRem, n, r32, ctx);
112 publicKey->modulus[i] = BN_get_word(rsaRem);
113 }
114 break;
115 }
116
117 BN_free(rsaR);
118 BN_free(rsaRR);
119 BN_free(n);
120 BN_free(r32);
121 BN_free(rsaN0inv);
122 BN_free(rsaRem);
123 BN_CTX_free(ctx);
124 return result;
125 }
126
GetUserInfo(char * buf,size_t len)127 int GetUserInfo(char *buf, size_t len)
128 {
129 char hostname[BUF_SIZE_DEFAULT];
130 char username[BUF_SIZE_DEFAULT];
131 uv_passwd_t pwd;
132 int ret = -1;
133 size_t bufSize = sizeof(hostname);
134 if (uv_os_gethostname(hostname, &bufSize) < 0 && EOK != strcpy_s(hostname, sizeof(hostname), "unknown")) {
135 return ERR_API_FAIL;
136 }
137 if (!uv_os_get_passwd(&pwd) && !strcpy_s(username, sizeof(username), pwd.username)) {
138 ret = 0;
139 }
140 uv_os_free_passwd(&pwd);
141 if (ret < 0 && EOK != strcpy_s(username, sizeof(username), "unknown")) {
142 return ERR_API_FAIL;
143 }
144 if (snprintf_s(buf, len, len - 1, " %s@%s", username, hostname) < 0) {
145 return ERR_BUF_OVERFLOW;
146 }
147 return RET_SUCCESS;
148 }
149
WritePublicKeyfile(RSA * private_key,const char * private_key_path)150 int WritePublicKeyfile(RSA *private_key, const char *private_key_path)
151 {
152 RSAPublicKey publicKey;
153 char info[BUF_SIZE_DEFAULT];
154 int ret = 0;
155 string path = private_key_path + string(".pub");
156
157 ret = RSA2RSAPublicKey(private_key, &publicKey);
158 if (!ret) {
159 WRITE_LOG(LOG_DEBUG, "Failed to convert to publickey\n");
160 return 0;
161 }
162 vector<uint8_t> vec = Base::Base64Encode((const uint8_t *)&publicKey, sizeof(RSAPublicKey));
163 if (!vec.size()) {
164 return 0;
165 }
166 GetUserInfo(info, sizeof(info));
167 vec.insert(vec.end(), (uint8_t *)info, (uint8_t *)info + strlen(info));
168 ret = Base::WriteBinFile(path.c_str(), vec.data(), vec.size(), true);
169 return ret >= 0 ? 1 : 0;
170 }
171
GenerateKey(const char * file)172 bool GenerateKey(const char *file)
173 {
174 EVP_PKEY *publicKey = EVP_PKEY_new();
175 BIGNUM *exponent = BN_new();
176 RSA *rsa = RSA_new();
177 int bits = 4096;
178 mode_t old_mask;
179 FILE *fKey = nullptr;
180 bool ret = false;
181
182 while (true) {
183 WRITE_LOG(LOG_DEBUG, "generate_key '%s'\n", file);
184 if (!publicKey || !exponent || !rsa) {
185 WRITE_LOG(LOG_DEBUG, "Failed to allocate key");
186 break;
187 }
188
189 BN_set_word(exponent, RSA_F4);
190 RSA_generate_key_ex(rsa, bits, exponent, nullptr);
191 EVP_PKEY_set1_RSA(publicKey, rsa);
192 old_mask = umask(077); // 077:permission
193
194 fKey = fopen(file, "w");
195 if (!fKey) {
196 WRITE_LOG(LOG_DEBUG, "Failed to open '%s'\n", file);
197 umask(old_mask);
198 break;
199 }
200 umask(old_mask);
201 if (!PEM_write_PrivateKey(fKey, publicKey, nullptr, nullptr, 0, nullptr, nullptr)) {
202 WRITE_LOG(LOG_DEBUG, "Failed to write key");
203 break;
204 }
205 if (!WritePublicKeyfile(rsa, file)) {
206 WRITE_LOG(LOG_DEBUG, "Failed to write public key");
207 break;
208 }
209 ret = true;
210 break;
211 }
212
213 EVP_PKEY_free(publicKey);
214 BN_free(exponent);
215 if (fKey)
216 fclose(fKey);
217 return ret;
218 }
219
ReadKey(const char * file,list<void * > * listPrivateKey)220 bool ReadKey(const char *file, list<void *> *listPrivateKey)
221 {
222 FILE *f = nullptr;
223 bool ret = false;
224
225 if (file == nullptr || listPrivateKey == nullptr) {
226 WRITE_LOG(LOG_FATAL, "file or listPrivateKey is null");
227 return ret;
228 }
229 while (true) {
230 if (!(f = fopen(file, "r"))) {
231 break;
232 }
233 RSA *rsa = RSA_new();
234 if (!PEM_read_RSAPrivateKey(f, &rsa, nullptr, nullptr)) {
235 RSA_free(rsa);
236 break;
237 }
238 listPrivateKey->push_back((void *)rsa);
239 ret = true;
240 break;
241 }
242 if (f) {
243 fclose(f);
244 }
245 return ret;
246 }
247
GetUserKeyPath(string & path)248 int GetUserKeyPath(string &path)
249 {
250 struct stat status;
251 const char harmoneyPath[] = ".harmony";
252 const char hdcKeyFile[] = "hdckey";
253 char buf[BUF_SIZE_DEFAULT];
254 size_t len = BUF_SIZE_DEFAULT;
255 // $home
256 if (uv_os_homedir(buf, &len) < 0)
257 return false;
258 string dir = string(buf) + Base::GetPathSep() + string(harmoneyPath) + Base::GetPathSep();
259 path = Base::CanonicalizeSpecPath(dir);
260 if (stat(path.c_str(), &status)) {
261 uv_fs_t req;
262 uv_fs_mkdir(nullptr, &req, path.c_str(), 0750, nullptr); // 0750:permission
263 uv_fs_req_cleanup(&req);
264 if (req.result < 0) {
265 WRITE_LOG(LOG_DEBUG, "Cannot mkdir '%s'", path.c_str());
266 return false;
267 }
268 }
269 path += hdcKeyFile;
270 return true;
271 }
272
LoadHostUserKey(list<void * > * listPrivateKey)273 bool LoadHostUserKey(list<void *> *listPrivateKey)
274 {
275 struct stat status;
276 string path;
277 if (!GetUserKeyPath(path)) {
278 return false;
279 }
280 if (stat(path.c_str(), &status) == -1) {
281 if (!GenerateKey(path.c_str())) {
282 WRITE_LOG(LOG_DEBUG, "Failed to generate new key");
283 return false;
284 }
285 }
286 if (!ReadKey(path.c_str(), listPrivateKey)) {
287 return false;
288 }
289 return true;
290 }
291
AuthSign(void * rsa,const unsigned char * token,size_t tokenSize,void * sig)292 int AuthSign(void *rsa, const unsigned char *token, size_t tokenSize, void *sig)
293 {
294 unsigned int len;
295 if (!RSA_sign(NID_sha256, token, tokenSize, (unsigned char *)sig, &len, (RSA *)rsa)) {
296 return 0;
297 }
298 return (int)len;
299 }
300
GetPublicKeyFileBuf(unsigned char * data,size_t len)301 int GetPublicKeyFileBuf(unsigned char *data, size_t len)
302 {
303 string path;
304 int ret;
305
306 if (!GetUserKeyPath(path)) {
307 return 0;
308 }
309 path += ".pub";
310 ret = Base::ReadBinFile(path.c_str(), (void **)data, len);
311 if (ret <= 0) {
312 return 0;
313 }
314 data[ret] = '\0';
315 return ret + 1;
316 }
317
318 #else // daemon
319
RSAPublicKey2RSA(const uint8_t * keyBuf,RSA ** key)320 bool RSAPublicKey2RSA(const uint8_t *keyBuf, RSA **key)
321 {
322 const int pubKeyModulusSize = 256;
323 const int pubKeyModulusSizeWords = pubKeyModulusSize / 4;
324
325 const RSAPublicKey *keyStruct = reinterpret_cast<const RSAPublicKey *>(keyBuf);
326 bool ret = false;
327 uint8_t modulusBuffer[pubKeyModulusSize];
328 RSA *newKey = RSA_new();
329 if (!newKey) {
330 goto cleanup;
331 }
332 if (keyStruct->wordModulusSize != pubKeyModulusSizeWords) {
333 goto cleanup;
334 }
335 if (memcpy_s(modulusBuffer, sizeof(modulusBuffer), keyStruct->modulus, sizeof(modulusBuffer)) != EOK) {
336 goto cleanup;
337 }
338 Base::ReverseBytes(modulusBuffer, sizeof(modulusBuffer));
339
340 #ifdef OPENSSL_IS_BORINGSSL
341 // boringssl
342 newKey->n = BN_bin2bn(modulusBuffer, sizeof(modulusBuffer), nullptr);
343 newKey->e = BN_new();
344 if (!newKey->e || !BN_set_word(newKey->e, keyStruct->exponent) || !newKey->n) {
345 goto cleanup;
346 }
347 #else
348 // openssl
349 #if OPENSSL_VERSION_NUMBER >= 0x10100005L
350 RSA_set0_key(newKey, BN_bin2bn(modulusBuffer, sizeof(modulusBuffer), nullptr), BN_new(), BN_new());
351 #else
352 newKey->n = BN_bin2bn(modulusBuffer, sizeof(modulusBuffer), nullptr);
353 newKey->e = BN_new();
354 if (!newKey->e || !BN_set_word(newKey->e, keyStruct->exponent) || !newKey->n) {
355 goto cleanup;
356 }
357 #endif
358 #endif
359
360 *key = newKey;
361 ret = true;
362
363 cleanup:
364 if (!ret && newKey) {
365 RSA_free(newKey);
366 }
367 return ret;
368 }
369
ReadDaemonKeys(const char * file,list<void * > * listPublicKey)370 void ReadDaemonKeys(const char *file, list<void *> *listPublicKey)
371 {
372 char buf[BUF_SIZE_DEFAULT2] = { 0 };
373 char *sep = nullptr;
374 int ret;
375 FILE *f = fopen(file, "re");
376 if (!f) {
377 WRITE_LOG(LOG_DEBUG, "Can't open '%s'", file);
378 return;
379 }
380 while (fgets(buf, sizeof(buf), f)) {
381 RSAPublicKey *key = new RSAPublicKey();
382 if (!key) {
383 break;
384 }
385 sep = strpbrk(buf, " \t");
386 if (sep) {
387 *sep = '\0';
388 }
389 ret = Base::Base64DecodeBuf(reinterpret_cast<uint8_t *>(buf), strlen(buf), reinterpret_cast<uint8_t *>(key));
390 if (ret != sizeof(RSAPublicKey)) {
391 WRITE_LOG(LOG_DEBUG, "%s: Invalid base64 data ret=%d", file, ret);
392 delete key;
393 continue;
394 }
395
396 if (key->wordModulusSize != RSANUMWORDS) {
397 WRITE_LOG(LOG_DEBUG, "%s: Invalid key len %d\n", file, key->wordModulusSize);
398 delete key;
399 continue;
400 }
401 listPublicKey->push_back(key);
402 }
403 fclose(f);
404 }
405
AuthVerify(uint8_t * token,uint8_t * sig,int siglen)406 bool AuthVerify(uint8_t *token, uint8_t *sig, int siglen)
407 {
408 list<void *> listPublicKey;
409 uint8_t authKeyIndex = 0;
410 void *ptr = nullptr;
411 int ret = 0;
412 int childRet = 0;
413 while (KeylistIncrement(&listPublicKey, authKeyIndex, &ptr)) {
414 RSA *rsa = nullptr;
415 if (!RSAPublicKey2RSA((const uint8_t *)ptr, &rsa)) {
416 break;
417 }
418 childRet = RSA_verify(NID_sha256, reinterpret_cast<const unsigned char *>(token),
419 RSA_TOKEN_SIZE, reinterpret_cast<const unsigned char *>(sig),
420 siglen, rsa);
421 RSA_free(rsa);
422 if (childRet) {
423 ret = 1;
424 break;
425 }
426 }
427 FreeKey(true, &listPublicKey);
428 return ret;
429 }
430
LoadDaemonKey(list<void * > * listPublicKey)431 void LoadDaemonKey(list<void *> *listPublicKey)
432 {
433 #ifdef HDC_PCDEBUG
434 char keyPaths[][BUF_SIZE_SMALL] = { "/root/.harmony/hdckey.pub" };
435 #else
436 char keyPaths[][BUF_SIZE_SMALL] = { "/hdc_keys", "/data/misc/hdc/hdc_keys" };
437 #endif
438 int num = sizeof(keyPaths) / sizeof(keyPaths[0]);
439 struct stat buf;
440
441 for (int i = 0; i < num; ++i) {
442 char *p = keyPaths[i];
443 if (!stat(p, &buf)) {
444 WRITE_LOG(LOG_DEBUG, "Loading keys from '%s'", p);
445 ReadDaemonKeys(p, listPublicKey);
446 }
447 }
448 }
449
PostUIConfirm(string publicKey)450 bool PostUIConfirm(string publicKey)
451 {
452 // Because the Hi3516 development board has no UI support for the time being, all public keys are received and
453 // By default, the system UI will record the public key /data/misc/hdc/hdckey/data/misc/hdc/hdckey
454 return true;
455 }
456 #endif // HDC_HOST
457
458 // --------------------------------------common code------------------------------------------
KeylistIncrement(list<void * > * listKey,uint8_t & authKeyIndex,void ** out)459 bool KeylistIncrement(list<void *> *listKey, uint8_t &authKeyIndex, void **out)
460 {
461 if (!listKey->size()) {
462 #ifdef HDC_HOST
463 LoadHostUserKey(listKey);
464 #else
465 LoadDaemonKey(listKey);
466 #endif
467 }
468 if (authKeyIndex == listKey->size()) {
469 // all finish
470 return false;
471 }
472 auto listIndex = listKey->begin();
473 std::advance(listIndex, ++authKeyIndex);
474 *out = *listIndex;
475 if (!*out) {
476 return false;
477 }
478 return true;
479 }
480
FreeKey(bool publicOrPrivate,list<void * > * listKey)481 void FreeKey(bool publicOrPrivate, list<void *> *listKey)
482 {
483 for (auto &&v : *listKey) {
484 if (publicOrPrivate) {
485 delete (RSAPublicKey *)v;
486 v = nullptr;
487 } else {
488 RSA_free((RSA *)v);
489 v = nullptr;
490 }
491 }
492 listKey->clear();
493 }
494 }
495