From 998d02dc6d17495ddfe7f51ca4e182d159ef60fe Mon Sep 17 00:00:00 2001 From: Sorin Jianu Date: Tue, 31 May 2016 17:19:32 -0700 Subject: [PATCH] Integrate changes up to 120560961 (1.3.30.3) --- CHANGELOG.txt | 72 +- omaha/base/security/aes.c | 175 ---- omaha/base/security/aes.h | 37 - omaha/base/security/b64.c | 88 -- omaha/base/security/b64.h | 38 - omaha/base/security/build.scons | 7 - omaha/base/security/challenger.cc | 87 -- omaha/base/security/challenger.h | 50 -- omaha/base/security/client-kat-unittest.sh | 54 -- omaha/base/security/client-server-regtest.sh | 125 --- omaha/base/security/client-server-unittest.sh | 96 -- omaha/base/security/hmac.c | 11 +- omaha/base/security/hmac.h | 12 +- omaha/base/security/hmac_unittest.cc | 2 +- omaha/base/security/keytool.cc | 254 ------ omaha/base/security/md5.c | 16 +- omaha/base/security/md5.h | 8 +- omaha/base/security/p224.h | 62 -- omaha/base/security/p224_ec.c | 850 ------------------ omaha/base/security/p224_ec_unittest.c | 814 ----------------- omaha/base/security/p256.c | 2 + omaha/base/security/p256_ecdsa.c | 2 +- omaha/base/security/p256_prng.c | 4 +- omaha/base/security/p256_unittest.c | 136 +++ omaha/base/security/pbkdf2.c | 81 -- omaha/base/security/pbkdf2.h | 36 - omaha/base/security/pbkdf2_test.cc | 112 --- omaha/base/security/publickey.h | 1 - omaha/base/security/rc4.c | 84 -- omaha/base/security/rc4.h | 40 - omaha/base/security/rsa.cc | 290 ------ omaha/base/security/rsa.h | 67 -- omaha/base/security/sha256.c | 10 +- omaha/base/security/sha256.h | 8 +- omaha/base/security/sha256_unittest.cc | 2 +- omaha/base/security/testclient.cc | 135 --- omaha/base/security/testdata/privatekey.4 | 15 - omaha/base/security/testdata/publickey.4.h | 1 - omaha/base/signatures.cc | 2 +- omaha/client/install.cc | 4 +- omaha/client/install_apps.cc | 4 +- omaha/client/install_self.cc | 9 +- omaha/common/app_registry_utils.cc | 65 ++ omaha/common/app_registry_utils.h | 14 + omaha/common/app_registry_utils_unittest.cc | 125 +-- omaha/common/config_manager.cc | 7 +- omaha/common/config_manager_unittest.cc | 7 + omaha/common/goopdate_utils.cc | 3 + omaha/common/ping.cc | 251 ++++-- omaha/common/ping.h | 56 +- omaha/common/ping_test.cc | 222 +++-- omaha/common/protocol_definition.h | 8 + omaha/common/update_request.cc | 17 +- omaha/common/update_request.h | 5 + omaha/common/web_services_client.cc | 35 +- omaha/common/web_services_client.h | 18 +- omaha/common/xml_const.cc | 2 + omaha/common/xml_const.h | 2 + omaha/common/xml_parser.cc | 33 + omaha/common/xml_parser_unittest.cc | 11 +- omaha/goopdate/app.cc | 3 + omaha/goopdate/app.h | 7 +- omaha/goopdate/app_bundle.cc | 47 +- omaha/goopdate/app_bundle.h | 13 + omaha/goopdate/app_command_ping_delegate.cc | 2 +- omaha/goopdate/app_manager.cc | 57 +- .../goopdate/app_state_checking_for_update.cc | 39 + .../goopdate/app_state_checking_for_update.h | 1 + omaha/goopdate/app_unittest_base.h | 2 +- omaha/goopdate/goopdate.cc | 4 + omaha/goopdate/goopdate_metrics.cc | 3 + omaha/goopdate/goopdate_metrics.h | 3 + .../goopdateres/generated_resources_am.rc | Bin 23916 -> 24080 bytes .../goopdateres/generated_resources_ar.rc | Bin 23228 -> 23366 bytes .../goopdateres/generated_resources_bg.rc | Bin 26056 -> 26206 bytes .../goopdateres/generated_resources_bn.rc | Bin 26174 -> 26330 bytes .../goopdateres/generated_resources_ca.rc | Bin 26090 -> 26074 bytes .../goopdateres/generated_resources_cs.rc | Bin 25022 -> 25184 bytes .../goopdateres/generated_resources_da.rc | Bin 25070 -> 25212 bytes .../goopdateres/generated_resources_de.rc | Bin 27042 -> 27138 bytes .../goopdateres/generated_resources_el.rc | Bin 26684 -> 26808 bytes .../goopdateres/generated_resources_en-GB.rc | Bin 24166 -> 24266 bytes .../goopdateres/generated_resources_en.rc | Bin 24218 -> 24238 bytes .../goopdateres/generated_resources_es-419.rc | Bin 25492 -> 25590 bytes .../goopdateres/generated_resources_es.rc | Bin 26950 -> 27058 bytes .../goopdateres/generated_resources_et.rc | Bin 24404 -> 24488 bytes .../goopdateres/generated_resources_fa.rc | Bin 24110 -> 24204 bytes .../goopdateres/generated_resources_fi.rc | Bin 25064 -> 25086 bytes .../goopdateres/generated_resources_fil.rc | Bin 25912 -> 26082 bytes .../goopdateres/generated_resources_fr.rc | Bin 26662 -> 26588 bytes .../goopdateres/generated_resources_gu.rc | Bin 26316 -> 26472 bytes .../goopdateres/generated_resources_hi.rc | Bin 24986 -> 25040 bytes .../goopdateres/generated_resources_hr.rc | Bin 25482 -> 25452 bytes .../goopdateres/generated_resources_hu.rc | Bin 25544 -> 25564 bytes .../goopdateres/generated_resources_id.rc | Bin 24374 -> 24428 bytes .../goopdateres/generated_resources_is.rc | Bin 24774 -> 24848 bytes .../goopdateres/generated_resources_it.rc | Bin 26376 -> 26454 bytes .../goopdateres/generated_resources_iw.rc | Bin 22646 -> 22748 bytes .../goopdateres/generated_resources_ja.rc | Bin 21288 -> 21318 bytes .../goopdateres/generated_resources_kn.rc | Bin 26620 -> 26792 bytes .../goopdateres/generated_resources_ko.rc | Bin 20676 -> 20718 bytes .../goopdateres/generated_resources_lt.rc | Bin 24436 -> 24496 bytes .../goopdateres/generated_resources_lv.rc | Bin 25752 -> 25824 bytes .../goopdateres/generated_resources_ml.rc | Bin 27910 -> 28066 bytes .../goopdateres/generated_resources_mr.rc | Bin 26106 -> 26262 bytes .../goopdateres/generated_resources_ms.rc | Bin 24604 -> 24670 bytes .../goopdateres/generated_resources_nl.rc | Bin 25906 -> 25962 bytes .../goopdateres/generated_resources_no.rc | Bin 25128 -> 25182 bytes .../goopdateres/generated_resources_pl.rc | Bin 25586 -> 25660 bytes .../goopdateres/generated_resources_pt-BR.rc | Bin 25166 -> 25274 bytes .../goopdateres/generated_resources_pt-PT.rc | Bin 25292 -> 25368 bytes .../goopdateres/generated_resources_ro.rc | Bin 25694 -> 25828 bytes .../goopdateres/generated_resources_ru.rc | Bin 24614 -> 24588 bytes .../goopdateres/generated_resources_sk.rc | Bin 25058 -> 25136 bytes .../goopdateres/generated_resources_sl.rc | Bin 25390 -> 25428 bytes .../goopdateres/generated_resources_sr.rc | Bin 25130 -> 25236 bytes .../goopdateres/generated_resources_sv.rc | Bin 25188 -> 25306 bytes .../goopdateres/generated_resources_sw.rc | Bin 26428 -> 26582 bytes .../goopdateres/generated_resources_ta.rc | Bin 26994 -> 27150 bytes .../goopdateres/generated_resources_te.rc | Bin 26360 -> 26516 bytes .../goopdateres/generated_resources_th.rc | Bin 23882 -> 23966 bytes .../goopdateres/generated_resources_tr.rc | Bin 25196 -> 25272 bytes .../goopdateres/generated_resources_uk.rc | Bin 24778 -> 24900 bytes .../goopdateres/generated_resources_ur.rc | Bin 24944 -> 24982 bytes .../goopdateres/generated_resources_vi.rc | Bin 24642 -> 24682 bytes .../goopdateres/generated_resources_zh-CN.rc | Bin 18946 -> 18962 bytes .../goopdateres/generated_resources_zh-TW.rc | Bin 19030 -> 19060 bytes .../resources/goopdateres/goopdate.grh | 10 +- omaha/goopdate/update_response_utils.cc | 54 ++ omaha/goopdate/update_response_utils.h | 8 + .../update_response_utils_unittest.cc | 104 +++ omaha/goopdate/worker.cc | 75 +- omaha/goopdate/worker.h | 3 - omaha/goopdate/worker_unittest.cc | 6 +- omaha/internal/grit/goopdateres.grd | 8 +- omaha/net/cup_ecdsa_pubkey.6.h | 31 + omaha/net/cup_ecdsa_request.cc | 2 +- omaha/net/cup_ecdsa_utils_unittest.cc | 2 +- omaha/net/network_request_impl.cc | 9 +- omaha/net/network_request_impl.h | 9 +- omaha/net/simple_request_unittest.cc | 16 +- .../client/google_update_recovery_unittest.cc | 74 +- omaha/setup/setup.cc | 4 +- omaha/setup/setup_metrics.cc | 3 + omaha/setup/setup_metrics.h | 3 + omaha/site_scons/site_tools/omaha_builders.py | 2 +- omaha/ui/splash_screen.cc | 3 +- omaha/ui/splash_screen_test.cc | 8 +- 148 files changed, 1274 insertions(+), 4125 deletions(-) delete mode 100644 omaha/base/security/aes.c delete mode 100644 omaha/base/security/aes.h delete mode 100644 omaha/base/security/b64.c delete mode 100644 omaha/base/security/b64.h delete mode 100644 omaha/base/security/challenger.cc delete mode 100644 omaha/base/security/challenger.h delete mode 100644 omaha/base/security/client-kat-unittest.sh delete mode 100644 omaha/base/security/client-server-regtest.sh delete mode 100644 omaha/base/security/client-server-unittest.sh delete mode 100644 omaha/base/security/keytool.cc delete mode 100644 omaha/base/security/p224.h delete mode 100644 omaha/base/security/p224_ec.c delete mode 100644 omaha/base/security/p224_ec_unittest.c create mode 100644 omaha/base/security/p256_unittest.c delete mode 100644 omaha/base/security/pbkdf2.c delete mode 100644 omaha/base/security/pbkdf2.h delete mode 100644 omaha/base/security/pbkdf2_test.cc delete mode 100644 omaha/base/security/publickey.h delete mode 100644 omaha/base/security/rc4.c delete mode 100644 omaha/base/security/rc4.h delete mode 100644 omaha/base/security/rsa.cc delete mode 100644 omaha/base/security/rsa.h delete mode 100644 omaha/base/security/testclient.cc delete mode 100644 omaha/base/security/testdata/privatekey.4 delete mode 100644 omaha/base/security/testdata/publickey.4.h create mode 100644 omaha/net/cup_ecdsa_pubkey.6.h diff --git a/CHANGELOG.txt b/CHANGELOG.txt index c2e0a9208..dee2d0b26 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -1,18 +1,74 @@ +## 2016-05-31 @113564071,120560961 1.3.30.3 + +### Changes +-------------------------------------------------------------------------------- +Allow persisting pings in background cases where the user token is a medium +integrity token. We now persist pings at high integrity in the machine case. +-------------------------------------------------------------------------------- +Add CUP key 6. +-------------------------------------------------------------------------------- +Add Google Update configuration and statistics metrics. This change unifies +the added metrics under a single key that also includes other Omaha metrics. +-------------------------------------------------------------------------------- +Omaha Client Doesn't Stop Fallbacks on X-Retry-After. The client was trying +(and failing) to save the RetryAfter value from medium integrity in the Machine +Omaha case. Now we save it from high integrity. +-------------------------------------------------------------------------------- +x-retry-after is obeyed even on http. The original HTTPS URL was being used +instead of the actual HTTP URL. Changed variable names to better reflect what +they represent. +-------------------------------------------------------------------------------- +Add a element for the update . The +element is expected to be added only to offline update response files that ship +with the standalone and msi installers. + +The element specifies the minimum requirements in terms of +platform, arch, and version. For systems that do not meet the +specifications, Omaha will error out with GOOPDATE_E_OS_NOT_SUPPORTED. +The service pack is ignored at the moment. + +An example element is shown below: + + +This sets the system requirements as Windows, x86 (or x64, since x64 systems support +x86 applications), and a minimum OS version of 6.0. +-------------------------------------------------------------------------------- +Retry-After should account for incorrect clock times. To account for clocks that +get reset to the past, Omaha will retry now if the retry time is more than +24 hours in the future. +-------------------------------------------------------------------------------- +Omaha UI: Downloading text needs changes. +-------------------------------------------------------------------------------- +Send cohort data with Omaha self-update pings as well as with exception/debug pings +such as when Omaha could not install itself or CUP failure pings. +-------------------------------------------------------------------------------- +Debug logging change. +-------------------------------------------------------------------------------- +Reliable pings in Omaha. This feature makes all pings persisted objects. If for +some reason Omaha is unable to transmit pings, the persisted pings are +transmitted the next time the Omaha UA process runs. +-------------------------------------------------------------------------------- +This change switches the ClickOnce single-sign timestamp servers to ComodoCA. +This makes all the time stamp servers use ComodoCA. +-------------------------------------------------------------------------------- +Integrate changes and delete unused code in base/security +-------------------------------------------------------------------------------- + ## 2016-02-03 @109823444,113564071 1.3.29.5 -------------------------------------------------------------------------------- Change cacheable URL GPO reg value from "PayloadType" to "DownloadPreference". --------------------------------------------------------------------------------- -Change to ::GetModuleHandle() instead of ::LoadLibrary() when getting a resource +-------------------------------------------------------------------------------- +Change to ::GetModuleHandle() instead of ::LoadLibrary() when getting a resource from goopdate.dll. The DLL is already loaded in memory, so LL is not needed. -------------------------------------------------------------------------------- -Mitigate DLL highjacking in the Omaha client. We now call ::SetDefaultDllDirectories -to retrict DLL loads to either full paths or %SYSTEM32%. ::SetDefaultDllDirectories -is available on Windows 8.1 and above, and on Windows Vista and above +Mitigate DLL highjacking in the Omaha client. We now call ::SetDefaultDllDirectories +to retrict DLL loads to either full paths or %SYSTEM32%. ::SetDefaultDllDirectories +is available on Windows 8.1 and above, and on Windows Vista and above when KB2533623 is applied. --------------------------------------------------------------------------------- -Update the build files to use the new DualSignedBinary function. This function +-------------------------------------------------------------------------------- +Update the build files to use the new DualSignedBinary function. This function signs binaries with both SHA1 and SHA256 certificates. --------------------------------------------------------------------------------- +-------------------------------------------------------------------------------- ## 2015-12-09 @109823443,110222497 1.3.29.1 -------------------------------------------------------------------------------- diff --git a/omaha/base/security/aes.c b/omaha/base/security/aes.c deleted file mode 100644 index 624fa5095..000000000 --- a/omaha/base/security/aes.c +++ /dev/null @@ -1,175 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#include "aes.h" - -#include -#include -#include -#include - -static const uint8_t sbox_e[256]= { - 99 , 124 , 119 , 123 , 242 , 107 , 111 , 197 - , 48 , 1 , 103 , 43 , 254 , 215 , 171 , 118 - , 202 , 130 , 201 , 125 , 250 , 89 , 71 , 240 - , 173 , 212 , 162 , 175 , 156 , 164 , 114 , 192 - , 183 , 253 , 147 , 38 , 54 , 63 , 247 , 204 - , 52 , 165 , 229 , 241 , 113 , 216 , 49 , 21 - , 4 , 199 , 35 , 195 , 24 , 150 , 5 , 154 - , 7 , 18 , 128 , 226 , 235 , 39 , 178 , 117 - , 9 , 131 , 44 , 26 , 27 , 110 , 90 , 160 - , 82 , 59 , 214 , 179 , 41 , 227 , 47 , 132 - , 83 , 209 , 0 , 237 , 32 , 252 , 177 , 91 - , 106 , 203 , 190 , 57 , 74 , 76 , 88 , 207 - , 208 , 239 , 170 , 251 , 67 , 77 , 51 , 133 - , 69 , 249 , 2 , 127 , 80 , 60 , 159 , 168 - , 81 , 163 , 64 , 143 , 146 , 157 , 56 , 245 - , 188 , 182 , 218 , 33 , 16 , 255 , 243 , 210 - , 205 , 12 , 19 , 236 , 95 , 151 , 68 , 23 - , 196 , 167 , 126 , 61 , 100 , 93 , 25 , 115 - , 96 , 129 , 79 , 220 , 34 , 42 , 144 , 136 - , 70 , 238 , 184 , 20 , 222 , 94 , 11 , 219 - , 224 , 50 , 58 , 10 , 73 , 6 , 36 , 92 - , 194 , 211 , 172 , 98 , 145 , 149 , 228 , 121 - , 231 , 200 , 55 , 109 , 141 , 213 , 78 , 169 - , 108 , 86 , 244 , 234 , 101 , 122 , 174 , 8 - , 186 , 120 , 37 , 46 , 28 , 166 , 180 , 198 - , 232 , 221 , 116 , 31 , 75 , 189 , 139 , 138 - , 112 , 62 , 181 , 102 , 72 , 3 , 246 , 14 - , 97 , 53 , 87 , 185 , 134 , 193 , 29 , 158 - , 225 , 248 , 152 , 17 , 105 , 217 , 142 , 148 - , 155 , 30 , 135 , 233 , 206 , 85 , 40 , 223 - , 140 , 161 , 137 , 13 , 191 , 230 , 66 , 104 - , 65 , 153 , 45 , 15 , 176 , 84 , 187 , 22 - }; - -static uint8_t xtime(uint32_t in) { - in &= 255; - in <<= 1; - in ^= 0x11b * (in >> 8); - return (uint8_t)in; - } - -static void expand_key(const uint8_t* key, uint32_t* expanded_key) { - int nrounds; - union { - uint8_t b[16]; - uint32_t w[4]; - } W; - uint8_t xor_val = 1; - - memcpy( &W, key, 16 ); - memcpy( expanded_key, &W, 16 ); - - for( nrounds = 0; nrounds < 10; ++nrounds ) { - - // update key schedule - W.b[0] ^= sbox_e[W.b[12+1]] ^ xor_val; - W.b[1] ^= sbox_e[W.b[12+2]]; - W.b[2] ^= sbox_e[W.b[12+3]]; - W.b[3] ^= sbox_e[W.b[12+0]]; - W.w[1] ^= W.w[0]; - W.w[2] ^= W.w[1]; - W.w[3] ^= W.w[2]; - - xor_val = xtime( xor_val ); - - expanded_key += 4; - memcpy( expanded_key, &W, 16 ); - } - } - -void AES_encrypt_block(const uint8_t* key, const uint8_t* in, uint8_t* out) { - int j, nrounds; - union { - uint8_t b[16]; - uint32_t w[4]; - } rd_state; - uint32_t expanded_key[11 * 4]; - uint32_t* expkey = &expanded_key[0]; - - expand_key( key, expanded_key ); - - memcpy( &rd_state, in, 16 ); - - // xor with initial key - rd_state.w[0] ^= *expkey++; - rd_state.w[1] ^= *expkey++; - rd_state.w[2] ^= *expkey++; - rd_state.w[3] ^= *expkey++; - - nrounds = 10; - - do { - uint8_t tmp; - - // bytesub && shiftrow - - // 1st - rd_state.b[0] = sbox_e[rd_state.b[0]]; - rd_state.b[4] = sbox_e[rd_state.b[4]]; - rd_state.b[8] = sbox_e[rd_state.b[8]]; - rd_state.b[12] = sbox_e[rd_state.b[12]]; - - // 2nd - tmp = rd_state.b[1]; - rd_state.b[1] = sbox_e[rd_state.b[5]]; - rd_state.b[5] = sbox_e[rd_state.b[9]]; - rd_state.b[9] = sbox_e[rd_state.b[13]]; - rd_state.b[13] = sbox_e[tmp]; - - // 3th - tmp = rd_state.b[2]; - rd_state.b[2] = sbox_e[rd_state.b[10]]; - rd_state.b[10] = sbox_e[tmp]; - tmp = rd_state.b[6]; - rd_state.b[6] = sbox_e[rd_state.b[14]]; - rd_state.b[14] = sbox_e[tmp]; - - // 4th - tmp = rd_state.b[3]; - rd_state.b[3] = sbox_e[rd_state.b[15]]; - rd_state.b[15] = sbox_e[rd_state.b[11]]; - rd_state.b[11] = sbox_e[rd_state.b[7]]; - rd_state.b[7] = sbox_e[tmp]; - - // mixcolumn except for last round - if( --nrounds ) { - for( j = 0; j < 16; j += 4 ) { - uint8_t tmp = - rd_state.b[j+0] ^ - rd_state.b[j+1] ^ - rd_state.b[j+2] ^ - rd_state.b[j+3]; - - rd_state.b[j+0] ^= xtime( rd_state.b[j+0] ^ rd_state.b[j+1] ) ^ tmp; - rd_state.b[j+1] ^= xtime( rd_state.b[j+1] ^ rd_state.b[j+2] ) ^ tmp; - rd_state.b[j+2] ^= xtime( rd_state.b[j+2] ^ rd_state.b[j+3] ) ^ tmp; - rd_state.b[j+3] = - rd_state.b[j+0] ^ - rd_state.b[j+1] ^ - rd_state.b[j+2] ^ - tmp; - } - } - - rd_state.w[0] ^= *expkey++; - rd_state.w[1] ^= *expkey++; - rd_state.w[2] ^= *expkey++; - rd_state.w[3] ^= *expkey++; - } while( nrounds ); - - memcpy( out, &rd_state, 16 ); -} diff --git a/omaha/base/security/aes.h b/omaha/base/security/aes.h deleted file mode 100644 index 97e945935..000000000 --- a/omaha/base/security/aes.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#ifndef OMAHA_BASE_SECURITY_AES_H_ -#define OMAHA_BASE_SECURITY_AES_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Encrypt a block. -// Both key and block size are 128 bits. -void AES_encrypt_block(const uint8_t* key, - const uint8_t* in, - uint8_t* out ); - -#define AES_BLOCK_SIZE 16 - -#ifdef __cplusplus -} -#endif - -#endif // OMAHA_BASE_SECURITY_AES_H_ diff --git a/omaha/base/security/b64.c b/omaha/base/security/b64.c deleted file mode 100644 index 2d95cfc43..000000000 --- a/omaha/base/security/b64.c +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#include "b64.h" - -static const char b64outmap[64] = { - 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', - 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', - 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', - 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-', '_' -}; - -static const char b64inmap[96] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 0, 0, - 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 0, 0, 0, 0, 0, 0, - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, - 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 0, 0, 0, 0, 64, - 0, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, - 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 0, 0, 0, 0, 0, -}; - -int B64_encode(const uint8_t* input, - int input_length, - char* output, - int output_max) { - unsigned int accu = 0; - int shift = 0; - int output_size = 0; - - while (input_length--) { - accu <<= 8; - accu |= *input++; - shift += 8; - - while (shift >= 6) { - if (output_size >= output_max) return -1; // out of output space - output[output_size++] = b64outmap[(accu >> (shift - 6)) & 63]; - shift -= 6; - } - } - if (shift) { - if (output_size >= output_max) return -1; // out of output space - accu <<= 8; // pad with 0 byte really - shift += 8; - output[output_size++] = b64outmap[(accu >> (shift - 6)) & 63]; - } - - // Output terminating 0 - if (output_size >= output_max) return -1; // out of output space - output[output_size] = '\0'; - - return output_size; -} - -int B64_decode(const char* input, - uint8_t* output, - int output_max) { - unsigned int accu = 0; - int shift = 0; - int output_size = 0; - - while (*input) { - unsigned char in = *input++ & 255; - if (in < 32 || in > 127 || !b64inmap[in - 32]) return -1; // invalid input - accu <<= 6; - accu |= (b64inmap[in - 32] - 1); - shift += 6; - if (shift >= 8) { - if (output_size >= output_max) return -1; // out of output space - output[output_size++] = (accu >> (shift - 8)) & 255; - shift -= 8; - } - } - return output_size; -} diff --git a/omaha/base/security/b64.h b/omaha/base/security/b64.h deleted file mode 100644 index cd65a6640..000000000 --- a/omaha/base/security/b64.h +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#ifndef OMAHA_BASE_SECURITY_B64_H_ -#define OMAHA_BASE_SECURITY_B64_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -int B64_encode(const uint8_t* input, - int input_length, - char* output, - int output_max); - -int B64_decode(const char* input, - uint8_t* output, - int output_max); - -#ifdef __cplusplus -} -#endif - -#endif // OMAHA_BASE_SECURITY_B64_H_ diff --git a/omaha/base/security/build.scons b/omaha/base/security/build.scons index bafdac6c0..81e7a13da 100644 --- a/omaha/base/security/build.scons +++ b/omaha/base/security/build.scons @@ -29,19 +29,13 @@ security_env.Append( ], ) - security_inputs = [ - 'aes.c', - 'b64.c', - 'challenger.cc', 'hmac.c', 'md5.c', 'p256.c', 'p256_ec.c', 'p256_ecdsa.c', 'p256_prng.c', - 'rc4.c', - 'rsa.cc', 'sha.c', 'sha256.c', ] @@ -50,4 +44,3 @@ security_inputs = [ security_env.ComponentStaticLibraryMultiarch('security', security_inputs, use_pch_default=False) - diff --git a/omaha/base/security/challenger.cc b/omaha/base/security/challenger.cc deleted file mode 100644 index 0927abcc4..000000000 --- a/omaha/base/security/challenger.cc +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#include "challenger.h" - -#include -#include -#include - -#include "rsa.h" -#include "md5.h" -#include "aes.h" -#include "b64.h" - -// Windows compilers do not have C99 support yet. -#if defined(WIN32) || defined(_WIN32) -#ifndef snprintf -#define snprintf _snprintf -#endif -#endif - -Challenger::Challenger(RSA::PublicKey pkey, - const unsigned char* seed, int seed_size) - : rsa_(pkey) { - memset(count_, 0, sizeof(count_)); - // Use seed as key for AES. Compress seed first. - MD5_hash(seed, seed_size, seed_); -} - -const char* Challenger::challenge() { - uint8_t ctr[AES_BLOCK_SIZE]; - - // Compute current challenge. - AES_encrypt_block(seed_, count_, ctr); - - // Increment count for future fresh challenges. - for (size_t i = 0; i < sizeof(count_) && !++count_[i]; ++i); - - // Prepend our version number. - char* p = challenge_; - p += snprintf(challenge_, sizeof(challenge_), "%d:", rsa_.version()); - - // Append our current challenge. - B64_encode(ctr, - sizeof(ctr), - p, - static_cast(sizeof(challenge_) - (p - challenge_))); - - return challenge_; -} - -bool Challenger::verify(const char* hash, const char* signature) const { - char message[128]; - uint8_t sigbuf[128]; - - // Expect exactly 128 bytes of decoded signature data. - if (B64_decode(signature, sigbuf, sizeof(sigbuf)) != sizeof(sigbuf)) - return false; - - // Verify signature with baked-in public key and recover embedded message. - int result = rsa_.verify(sigbuf, sizeof(sigbuf), - message, sizeof(message) - 1); - - if (result < 0 || result >= static_cast(sizeof(message) - 1)) - return false; - - // Since we're expecting a textual message, 0-terminate it. - message[result] = '\0'; - - // Construct and compare expected against received signed message. - char expected[128]; - snprintf(expected, sizeof(expected), "%s:%s", challenge_, hash); - - return !strcmp(expected, message); -} diff --git a/omaha/base/security/challenger.h b/omaha/base/security/challenger.h deleted file mode 100644 index b5a81a083..000000000 --- a/omaha/base/security/challenger.h +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#ifndef OMAHA_BASE_SECURITY_CHALLENGER_H_ -#define OMAHA_BASE_SECURITY_CHALLENGER_H_ - -#include - -#include "md5.h" -#include "aes.h" -#include "rsa.h" - -class Challenger { - public: - // Instantiate internal PRNG with seed. Use a proper method on your - // target platform to collect some entropy. For windows for instance, - // use CryptoAPI; on unix, read some from /dev/urandom. - // 128 bits of entropy is plenty. - explicit Challenger(RSA::PublicKey public_key, - const uint8_t* seed, int seed_size); - - // Not a const method! Every call updates internal state and never - // are identical challenges returned. - // Returns WebSafe base64 encoded string. - const char* challenge(); - - // Verifies whether signature contains current challenge and hash. - // Arguments are expected to be WebSafe base64 encoded strings. - bool verify(const char* hash, const char* signature) const; - - private: - char challenge_[64]; - uint8_t count_[AES_BLOCK_SIZE]; - uint8_t seed_[MD5_DIGEST_SIZE]; - RSA rsa_; -}; - -#endif // OMAHA_BASE_SECURITY_CHALLENGER_H_ diff --git a/omaha/base/security/client-kat-unittest.sh b/omaha/base/security/client-kat-unittest.sh deleted file mode 100644 index e20659f50..000000000 --- a/omaha/base/security/client-kat-unittest.sh +++ /dev/null @@ -1,54 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#!/bin/bash -source googletest.sh || exit 1 - -KEYTOOL=$TEST_SRCDIR/google3/security/util/lite/keytool -TESTCLIENT=$TEST_SRCDIR/google3/security/util/lite/testclient -TESTCONTENT=$TEST_TMPDIR/testcontent -RANDOMSEED="Mon Oct 22 18:43:16 PDT 2007" -KEYVERSION=4 -PRIVKEY=$TEST_SRCDIR/google3/security/util/lite/testdata/privatekey - -# Known answer test (KAT) of private key to public key format conversion. -$KEYTOOL --key_version $KEYVERSION \ - --private_key_file $PRIVKEY \ - --pubout --output_file $TESTCONTENT \ - --unittest=true \ - || die "Failed to run $KEYTOOL" - -# KAT test encryption -ENCRYPTION=`$TESTCLIENT --encrypt "$RANDOMSEED" --seed "$RANDOMSEED"` \ - || die "Failed to run $TESTCLIENT" -EXPECTED="AAAAAAQ0-wpAgncQ457-1yEJ_qeZLNirhvaYAzLKNWPIXkWmb5KLVzX8tEHffxGRK9YeR0DQR5Opkn5jiN0VR50_XoCPiiT_4Kgwow0V-HR79T8K0dzcElXzqQmNIUa1dcOX3h_51zBZGe5e9K9DRP2V-cgeS4LQffDIMXPnnAqDfB56_e6AJYN8POgmnauqPUy79Fh1goKxFU4zBwUSQ_I" - -check_eq "$ENCRYPTION" "$EXPECTED" - -# Known answers the client should comply with, for a given seed. -CHALLENGE="4:hCjq6Wyx6yVzz1YALTRrFQ" - -check_eq "$CHALLENGE" `$TESTCLIENT --seed "$RANDOMSEED" --challenge` - -HASH="SXUB9-gk5BfYARXs2ESbJXsqhZk" -SIGNATURE="KprvUUUPkPMH9k8kmGGcUSplD4ww11zzk-eH-rej6NuZQ-jgKL0xqc2iCmXcpOpLLuLUAUtHkSdvhSrw_Hj6r-jRdQIyrOOQ28n2pLHqJPQMpP9xMTCNvH7KY8ZbJSMvW6zT3Pg4JoPMOS2hsM9yFs1OQyCgRd66r8GFTB9htjs" - -# Hand fixed signature to client to test, along with content to hash. -# Client will check hash against test content generated by keytool earlier. -$TESTCLIENT --seed "$RANDOMSEED" \ - --signature $SIGNATURE \ - --hash $HASH \ - --input_file $TESTCONTENT --verbose \ - || die "Failed to run $TESTCLIENT" diff --git a/omaha/base/security/client-server-regtest.sh b/omaha/base/security/client-server-regtest.sh deleted file mode 100644 index b355f570b..000000000 --- a/omaha/base/security/client-server-regtest.sh +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#!/bin/bash -source googletest.sh || exit 1 - -KEYTOOL=$TEST_SRCDIR/google3/security/util/lite/keytool -TESTCLIENT=$TEST_TMPDIR/testclient -RANDOMSEED=`date +%s-%N` # Crappy but changing seed. -TESTCONTENT=$TEST_TMPDIR/publickey.h -PRIVKEY=$TEST_TMPDIR/privatekey -SRCS="md5.h md5.c \ - sha.h sha.c \ - aes.h aes.c \ - rc4.h rc4.c \ - b64.h b64.c \ - rsa.h rsa.cc \ - hash-internal.h \ - challenger.h challenger.cc \ - testclient.cc" - -# $1 var to capture into -# $2 cmd to capture stdout from -function capture() { - eval $2 > /dev/null || die "Failed to run $2" - eval "$1=\"$(eval $2)\"" -# Sometimes (on my workstation) a SIGPIPE (13) results in stdout capture -# failing, when running a Google3 binary (i.e. not TESTCLIENT) -# So we retry. Error 141 is 128 + 13, bash reporting SIGPIPE. - while [ "$1" = "" ]; do - if [ $? -eq 0 -o $? -eq 141 ]; then - eval "$1=\"$(eval $2)\"" - else - eval "$1=\"(null:$?)\"" - fi - done -} - -# Copy source and Makefile to TMPDIR. -cd $TEST_SRCDIR/google3/security/util/lite || die "Cannot cd" -cp $SRCS $TEST_TMPDIR || die "Cannot cp files" -cd $TEST_TMPDIR || die "Cannot cd" - -for ((i=0;i<8;i+=1)); do -let "KEYVERSION = $i / 5" -let "rem = $i % 5" - -if [ "$rem" -eq 0 ]; then -# Use openssl to generate a random private key. -openssl genrsa -3 1024 > $PRIVKEY.$KEYVERSION || die "Cannot openssl" - -# Produce public key in compilable format. -$KEYTOOL --key_version $KEYVERSION \ - --private_key_file $PRIVKEY \ - --pubout --output_file $TESTCONTENT \ - || die "Failed to run $KEYTOOL" - -cat $TESTCONTENT || die "Cannot cat $TESTCONTENT" - -# Build fresh test client, plain C, C++, no google3 dependencies. -gcc md5.c sha.c aes.c b64.c rc4.c rsa.cc challenger.cc \ - testclient.cc -Wall -Os -I /usr/include -o testclient -lstdc++ \ - || die "Cannot compile" -fi - -# Morph seed. -RANDOMSEED=$RANDOMSEED.testing.$i -echo "Client seed: $RANDOMSEED" - -# Have client encrypt a message. -ENCRYPTION_CMD="$TESTCLIENT --encrypt \"$RANDOMSEED\" \ - --seed \"$RANDOMSEED\"" -capture ENCRYPTION "$ENCRYPTION_CMD" - -# Check server can decrypt the message. -DECRYPTION_CMD="$KEYTOOL --decrypt --input=\"$ENCRYPTION\"" -capture DECRYPTION "$DECRYPTION_CMD" - -check_eq "$DECRYPTION" "$RANDOMSEED" - -# Have client produce a challenge. -CHALLENGE_CMD="$TESTCLIENT --seed \"$RANDOMSEED\" --challenge" -capture CHALLENGE "$CHALLENGE_CMD" -echo "Client challenge: $CHALLENGE" - -# Compute hash of content. -HASH_CMD="$KEYTOOL --key_version $KEYVERSION \ - --input_file $TESTCONTENT --hashout \ - --private_key_file $PRIVKEY" -capture HASH "$HASH_CMD" -echo "Content hash: $HASH" - -# Have server sign challenge + hash. -SIGNATURE_CMD="$KEYTOOL --key_version $KEYVERSION \ - --input_file $TESTCONTENT \ - --challenge=\"$CHALLENGE\" --sigout \ - --private_key_file $PRIVKEY" -capture SIGNATURE "$SIGNATURE_CMD" - -echo "Server proof: $SIGNATURE" - -# Check client can verify signature. -VERIFY_CMD="$TESTCLIENT --seed \"$RANDOMSEED\" \ - --signature \"$SIGNATURE\" \ - --hash \"$HASH\" \ - --input_file $TESTCONTENT" -capture PASS "$VERIFY_CMD" - -check_eq "$PASS" "PASS" - -done - -echo $PASS diff --git a/omaha/base/security/client-server-unittest.sh b/omaha/base/security/client-server-unittest.sh deleted file mode 100644 index fb86398c7..000000000 --- a/omaha/base/security/client-server-unittest.sh +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#!/bin/bash -source googletest.sh || exit 1 - -KEYTOOL=$TEST_SRCDIR/google3/security/util/lite/keytool -TESTCLIENT=$TEST_SRCDIR/google3/security/util/lite/testclient -RANDOMSEED=`date +%s-%N` # Crappy but changing seed. -KEYVERSION=4 -TESTCONTENT=$TEST_TMPDIR/testcontent -PRIVKEY=$TEST_SRCDIR/google3/security/util/lite/testdata/privatekey - -# $1 var to capture into -# $2 cmd to capture stdout from -function capture() { - eval $2 > /dev/null || die "Failed to run $2" - eval "$1=\"$(eval $2)\"" -# Sometimes (on my workstation) a SIGPIPE (13) results in stdout capture -# failing, when running a Google3 binary (i.e. not TESTCLIENT) -# So we retry. Error 141 is 128 + 13, bash reporting SIGPIPE. - while [ "$1" = "" ]; do - if [ $? -eq 0 -o $? -eq 141 ]; then - eval "$1=\"$(eval $2)\"" - else - eval "$1=\"(null:$?)\"" - fi - done -} - -# Produce public key in compilable format. -$KEYTOOL --key_version=$KEYVERSION \ - --private_key_file=$PRIVKEY \ - --pubout --output_file $TESTCONTENT \ - --unittest \ - || die "Failed to run $KEYTOOL" -echo "Test content: " -cat $TESTCONTENT - -echo "Client seed: $RANDOMSEED" - -# Have client encrypt. -ENCRYPTION_CMD="$TESTCLIENT --seed \"$RANDOMSEED\" --encrypt \"$RANDOMSEED\"" -capture ENCRYPTION "$ENCRYPTION_CMD" -echo "Encryption: $ENCRYPTION" - -# Check we can decrypt. -DECRYPTION_CMD="$KEYTOOL --decrypt --input=\"$ENCRYPTION\" \ - --private_key_file=$PRIVKEY" -capture DECRYPTION "$DECRYPTION_CMD" -echo "Decryption: $DECRYPTION" - -check_eq "$DECRYPTION" "$RANDOMSEED" - -# Have client challenge. -CHALLENGE_CMD="$TESTCLIENT --seed \"$RANDOMSEED\" --challenge --verbose" -capture CHALLENGE "$CHALLENGE_CMD" -echo "Client challenge: $CHALLENGE" - -# Hash content. -HASH_CMD="$KEYTOOL --key_version $KEYVERSION \ - --input_file $TESTCONTENT --hashout \ - --private_key_file $PRIVKEY" -capture HASH "$HASH_CMD" -echo "Content hash: $HASH" - -# Sign challenge + hash. -SIGNATURE_CMD="$KEYTOOL --key_version $KEYVERSION \ - --input_file $TESTCONTENT \ - --challenge=\"$CHALLENGE\" --sigout \ - --private_key_file $PRIVKEY" -capture SIGNATURE "$SIGNATURE_CMD" -echo "Server proof: $SIGNATURE" - -# Check client can verify signature. -VERIFY_CMD="$TESTCLIENT --seed \"$RANDOMSEED\" \ - --signature \"$SIGNATURE\" \ - --hash \"$HASH\" \ - --input_file $TESTCONTENT" -capture PASS "$VERIFY_CMD" - -check_eq "$PASS" "PASS" - -echo $PASS diff --git a/omaha/base/security/hmac.c b/omaha/base/security/hmac.c index 7d388cea8..735791a07 100644 --- a/omaha/base/security/hmac.c +++ b/omaha/base/security/hmac.c @@ -18,11 +18,12 @@ #include "hmac.h" #include +#include #include "sha.h" #include "md5.h" #include "sha256.h" -static void HMAC_init(HMAC_CTX* ctx, const void* key, unsigned int len) { +static void HMAC_init(LITE_HMAC_CTX* ctx, const void* key, unsigned int len) { unsigned int i; memset(&ctx->opad[0], 0, sizeof(ctx->opad)); @@ -46,22 +47,22 @@ static void HMAC_init(HMAC_CTX* ctx, const void* key, unsigned int len) { } } -void HMAC_MD5_init(HMAC_CTX* ctx, const void* key, unsigned int len) { +void HMAC_MD5_init(LITE_HMAC_CTX* ctx, const void* key, unsigned int len) { MD5_init(&ctx->hash); HMAC_init(ctx, key, len); } -void HMAC_SHA_init(HMAC_CTX* ctx, const void* key, unsigned int len) { +void HMAC_SHA_init(LITE_HMAC_CTX* ctx, const void* key, unsigned int len) { SHA_init(&ctx->hash); HMAC_init(ctx, key, len); } -void HMAC_SHA256_init(HMAC_CTX* ctx, const void* key, unsigned int len) { +void HMAC_SHA256_init(LITE_HMAC_CTX* ctx, const void* key, unsigned int len) { SHA256_init(&ctx->hash); HMAC_init(ctx, key, len); } -const uint8_t* HMAC_final(HMAC_CTX* ctx) { +const uint8_t* HMAC_final(LITE_HMAC_CTX* ctx) { uint8_t digest[32]; // upto SHA2 memcpy(digest, HASH_final(&ctx->hash), (HASH_size(&ctx->hash) <= sizeof(digest) ? diff --git a/omaha/base/security/hmac.h b/omaha/base/security/hmac.h index 49bcf0742..4a667419b 100644 --- a/omaha/base/security/hmac.h +++ b/omaha/base/security/hmac.h @@ -23,15 +23,15 @@ extern "C" { #endif -typedef struct HMAC_CTX { +typedef struct LITE_HMAC_CTX { HASH_CTX hash; uint8_t opad[64]; -} HMAC_CTX; +} LITE_HMAC_CTX; -void HMAC_MD5_init(HMAC_CTX* ctx, const void* key, unsigned int len); -void HMAC_SHA_init(HMAC_CTX* ctx, const void* key, unsigned int len); -void HMAC_SHA256_init(HMAC_CTX* ctx, const void* key, unsigned int len); -const uint8_t* HMAC_final(HMAC_CTX* ctx); +void HMAC_MD5_init(LITE_HMAC_CTX* ctx, const void* key, unsigned int len); +void HMAC_SHA_init(LITE_HMAC_CTX* ctx, const void* key, unsigned int len); +void HMAC_SHA256_init(LITE_HMAC_CTX* ctx, const void* key, unsigned int len); +const uint8_t* HMAC_final(LITE_HMAC_CTX* ctx); #define HMAC_update(ctx, data, len) HASH_update(&(ctx)->hash, data, len) #define HMAC_size(ctx) HASH_size(&(ctx)->hash) diff --git a/omaha/base/security/hmac_unittest.cc b/omaha/base/security/hmac_unittest.cc index d23dbb3d3..0a5abd56c 100644 --- a/omaha/base/security/hmac_unittest.cc +++ b/omaha/base/security/hmac_unittest.cc @@ -120,7 +120,7 @@ NULL, TEST_F(HmacTest, RFC2202andRFC4131) { // This tests against the RFC2202 & RFC4131 test vectors - HMAC_CTX hmac; + LITE_HMAC_CTX hmac; for (const struct KAT* katp = KATS; katp->key; ++katp) { string key = katp->key[0] == diff --git a/omaha/base/security/keytool.cc b/omaha/base/security/keytool.cc deleted file mode 100644 index 32ef7bf9f..000000000 --- a/omaha/base/security/keytool.cc +++ /dev/null @@ -1,254 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== -// -// Generate key with 'openssl genrsa -3 1024 > private-key.N' with N the -// version number. - -#include -#include - -#include "base/commandlineflags.h" -#include "base/init_google.h" -#include "base/integral_types.h" -#include "base/logging.h" -#include "base/scoped_ptr.h" -#include "base/stringprintf.h" -#include "file/base/file.h" -#include "file/base/helpers.h" -#include "security/util/sha1.h" -#include "strings/escaping.h" -#include "strings/strutil.h" -#include "third_party/openssl/evp.h" // for OpenSSL_add_all_ciphers -#include "third_party/openssl/rc4.h" -#include "third_party/openssl/sha.h" -#include "util/sig/privatekey.h" -#include "util/sig/publickey.h" -#include "util/task/status.h" - -DEFINE_string(input, "", "base-64 encoded input to decrypt"); -DEFINE_string(input_file, "", "input file to hash, sign or decrypt"); -DEFINE_bool(pubout, false, "print publickey as C style array initializer"); -DEFINE_string(private_key_file, "privatekey", - "input base filename for private key;" - " .key_version gets appended."); -DEFINE_bool(sigout, false, "output signature in base-64"); -DEFINE_bool(hashout, false, "output content hash in base-64"); -DEFINE_string(challenge, "", "input challenge in base-64"); -DEFINE_string(key_version, "1", "input key version number"); -DEFINE_bool(decrypt, false, "decrypt input"); -DEFINE_string(output_file, "", "file to write to"); -DEFINE_bool(unittest, false, "suppress volatile output"); -DEFINE_bool(fail, false, "fail for testing"); - -// Little helper that writes to cout or --output_file -static void WriteOutput(const string& output) { - if (FLAGS_output_file.length()) { - CHECK_OK(file::SetContents(FLAGS_output_file, output, file::Defaults())); - } else { - cout << output; - flush(cout); - } -} - -static void ProcessCommandLine(const char* self) { - CHECK(!FLAGS_fail) << "Failing for testing."; - - string input; - if (FLAGS_input.length()) - CHECK(strings::WebSafeBase64Unescape(FLAGS_input, &input)); - // Input_file presence trumps challenge. - if (FLAGS_input_file.length()) - CHECK_OK(file::GetContents(FLAGS_input_file, &input, file::Defaults())); - - if (FLAGS_decrypt) { - CHECK_GE(input.length(), 1 + 4); - - // Check the wire-format. Currently, only 0 is understood. - CHECK_EQ(input.data()[0], 0); - - // Get key version. - unsigned int key_version = - ((input.data()[1] & 255) << 24) | - ((input.data()[2] & 255) << 16) | - ((input.data()[3] & 255) << 8) | - ((input.data()[4] & 255) << 0); - - string privkeyfile = FLAGS_private_key_file + "." + - SimpleItoa(key_version); - - // Get the right private key. - string privPEM; - CHECK_OK(file::GetContents(privkeyfile, &privPEM, file::Defaults())); - PrivateKey priv(privPEM.c_str()); - - CHECK_GE(input.length(), 1 + 4 + priv.RawSize()); - - // Unwrap RC4 key as encrypted with RSA. - string wrappedKey = input.substr(1 + 4, priv.RawSize()); - string keyAndHash; - CHECK(priv.RawDecrypt(wrappedKey, &keyAndHash)); - CHECK_EQ(keyAndHash.length(), priv.RawSize()); - - RC4_KEY rc4; - RC4_set_key(&rc4, - keyAndHash.length(), - reinterpret_cast(keyAndHash.data())); - - // Warm up RC4 by dropping 1536 bytes. - unsigned char wasted[1536]; - RC4(&rc4, sizeof(wasted), wasted, wasted); - - int len = input.length() - 1 - 4 - priv.RawSize(); - scoped_ptr buf(new char[len]); - - // Decrypt message. - RC4(&rc4, - len, - reinterpret_cast - (input.data() + 1 + 4 + priv.RawSize()), - reinterpret_cast(buf.get())); - - // Compute the mask which obscures the lsb plain hash value. - unsigned char mask[SHA_DIGEST_LENGTH]; - SHA1(reinterpret_cast(keyAndHash.data()), - priv.RawSize() - SHA_DIGEST_LENGTH, - mask); - - // Hash the decrypted output. - unsigned char hash[SHA_DIGEST_LENGTH]; - SHA1(reinterpret_cast(buf.get()), - len, - hash); - - // Mask the computed hash. - for (int i = 0; i < SHA_DIGEST_LENGTH; ++i) - hash[i] ^= mask[i]; - - // Check masked hash against one that was encrypted under RSA. - CHECK(!memcmp(hash, - keyAndHash.data() + priv.RawSize() - SHA_DIGEST_LENGTH, - SHA_DIGEST_LENGTH)); - - string output(buf.get(), len); - - WriteOutput(output); - return; - } - - string privPEM; - string privkeyfile = "(null)"; - - if (FLAGS_private_key_file.length()) { - privkeyfile = FLAGS_private_key_file + "." + FLAGS_key_version; - CHECK_OK(file::GetContents(privkeyfile, &privPEM, file::Defaults())); - } - - PrivateKey priv(privPEM.c_str()); - CHECK(priv.IsValid()) << "Failed to load private key from file " - << "\"" << privkeyfile << "\""; - - if (FLAGS_pubout) { - // Output the corresponding public in a format that can be - // compiled into the clientlibrary. Basically an initialized C array of - // uint32. - uint32 mod[2 * 64 + 1]; - int mod_size = sizeof(mod) / sizeof(mod[0]); - mod_size = priv.PrecomputedArrayInitializer(mod, mod_size); - CHECK(mod_size) << "PrecomputeArrayInitializer() failed: key too large?"; - // The public key format to embed into client code is: - // {version, modulus-length-in-words, } - string pub; - if (!FLAGS_unittest) { - StringAppendF(&pub, "/* generated with:\n" - "%s --private_key_file \"%s\" --key_version %s --pubout\n*/\n", - self, FLAGS_private_key_file.c_str(), FLAGS_key_version.c_str()); - } - StringAppendF(&pub, "{"); - StringAppendF(&pub, "%s,", FLAGS_key_version.c_str()); // version - StringAppendF(&pub, "%d,", - (mod_size - 1) / 2); // length of modulus in words - for (int i = 0; i < mod_size; ++i) { - if (i) StringAppendF(&pub, ","); - StringAppendF(&pub, "0x%08x", mod[i]); - } - StringAppendF(&pub, "}\n"); - - WriteOutput(pub); - return; - } - - // Hash content to sign. - security::SHA1 sha; - sha.Update(input.data(), input.size()); - string b64hash; - strings::WebSafeBase64Escape(sha.Digest(), &b64hash); - - LOG(INFO) << "Input hash: " << b64hash; - - if (FLAGS_hashout) { - string unb64hash; - CHECK(strings::WebSafeBase64Unescape(b64hash, &unb64hash)); - CHECK_EQ(unb64hash.length(), SHA_DIGEST_LENGTH); - - WriteOutput(b64hash); - return; - } - - // Sign concatenation of challenge and hash. - // In inefficient base64 format for ease of debugging. - string msg(FLAGS_challenge + ':' + b64hash); - - LOG(INFO) << "Message to be signed: " << msg; - - // At this point, look up / verify key version number. - // The client challenge has the form NN:XX with NN being its - // public key version number and XX being a random challenge. - // A normal server would have multiple active keys in a lookup structure. - // And would not CHECK input based failures ever, of course. - CHECK_EQ(FLAGS_challenge.find(FLAGS_key_version + ":"), 0); - - string signature; - CHECK(priv.SignAndEmbedMessage(msg, &signature)) << - "SignAndEmbedMessage() failed: input too large?"; - - CHECK_EQ(signature.length(), 128) << "1024 bit RSA keys only please"; - - string b64signature; - strings::WebSafeBase64Escape(signature, &b64signature); - - // Verify signature we made, paranoia check. - string verified; - string unb64signature; - CHECK(strings::WebSafeBase64Unescape(b64signature, &unb64signature)); - CHECK_EQ(unb64signature.length(), 128); - CHECK_EQ(unb64signature, signature); - CHECK(priv.VerifyAndRecoverMessage(unb64signature, &verified)); - CHECK_EQ(verified, msg); - - if (FLAGS_sigout) { - WriteOutput(b64signature); - return; - } -} - -int main(int argc, char* argv[]) { - InitGoogle("keytool", &argc, &argv, true); - - OpenSSL_add_all_ciphers(); - - ProcessCommandLine(argv[0]); - - return 0; -} diff --git a/omaha/base/security/md5.c b/omaha/base/security/md5.c index fb8de7ade..e2bd3150f 100644 --- a/omaha/base/security/md5.c +++ b/omaha/base/security/md5.c @@ -51,7 +51,7 @@ static const uint32_t KK[64] = 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 }; -static void MD5_Transform(MD5_CTX* ctx) { +static void MD5_Transform(LITE_MD5_CTX* ctx) { uint32_t W[64]; uint32_t A, B, C, D; uint8_t* p = ctx->buf; @@ -59,9 +59,9 @@ static void MD5_Transform(MD5_CTX* ctx) { for(t = 0; t < 16; ++t) { uint32_t tmp = *p++; - tmp |= *p++ << 8; - tmp |= *p++ << 16; - tmp |= *p++ << 24; + tmp |= (uint32_t)*p++ << 8u; + tmp |= (uint32_t)*p++ << 16u; + tmp |= (uint32_t)*p++ << 24u; W[t] = tmp; } @@ -109,7 +109,7 @@ static const HASH_VTAB MD5_VTAB = { MD5_DIGEST_SIZE }; -void MD5_init(MD5_CTX* ctx) { +void MD5_init(LITE_MD5_CTX* ctx) { ctx->f = &MD5_VTAB; ctx->state[0] = 0x67452301; ctx->state[1] = 0xEFCDAB89; @@ -119,7 +119,7 @@ void MD5_init(MD5_CTX* ctx) { } -void MD5_update(MD5_CTX* ctx, const void* data, unsigned int len) { +void MD5_update(LITE_MD5_CTX* ctx, const void* data, unsigned int len) { unsigned int i = (unsigned int)(ctx->count & 63); const uint8_t* p = (const uint8_t*)data; @@ -135,7 +135,7 @@ void MD5_update(MD5_CTX* ctx, const void* data, unsigned int len) { } -const uint8_t* MD5_final(MD5_CTX* ctx) { +const uint8_t* MD5_final(LITE_MD5_CTX* ctx) { uint8_t* p = ctx->buf; uint64_t cnt = ctx->count * 8; int i; @@ -163,7 +163,7 @@ const uint8_t* MD5_final(MD5_CTX* ctx) { /* Convenience function */ const uint8_t* MD5_hash(const void* data, unsigned int len, uint8_t* digest) { - MD5_CTX ctx; + LITE_MD5_CTX ctx; MD5_init(&ctx); MD5_update(&ctx, data, len); memcpy(digest, MD5_final(&ctx), MD5_DIGEST_SIZE); diff --git a/omaha/base/security/md5.h b/omaha/base/security/md5.h index 0141d34c7..1de3dceb2 100644 --- a/omaha/base/security/md5.h +++ b/omaha/base/security/md5.h @@ -23,11 +23,11 @@ extern "C" { #endif // __cplusplus -typedef HASH_CTX MD5_CTX; +typedef HASH_CTX LITE_MD5_CTX; -void MD5_init(MD5_CTX* ctx); -void MD5_update(MD5_CTX* ctx, const void* data, unsigned int len); -const uint8_t* MD5_final(MD5_CTX* ctx); +void MD5_init(LITE_MD5_CTX* ctx); +void MD5_update(LITE_MD5_CTX* ctx, const void* data, unsigned int len); +const uint8_t* MD5_final(LITE_MD5_CTX* ctx); // Convenience method. Returns digest address. // NOTE: *digest needs to hold MD5_DIGEST_SIZE bytes. diff --git a/omaha/base/security/p224.h b/omaha/base/security/p224.h deleted file mode 100644 index bc9c9f86f..000000000 --- a/omaha/base/security/p224.h +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#ifndef OMAHA_BASE_SECURITY_P224_H_ -#define OMAHA_BASE_SECURITY_P224_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef uint8_t u8; -typedef uint32_t u32; - -typedef struct { - u32 x[8], y[8], z[8]; -} p224_point; - -// Parse and check validity of a point from binary input. -// Input size should be 2 * 28 (56) bytes. -// Returns 0 on failure. -int p224_point_from_bin(const void* input, int size, p224_point* out); - -// Render a point to binary output. -// output should be able to hold 2 * 28 (56) bytes. -void p224_point_to_bin(const p224_point* in, void* output); - -// Multiply the curve generator by scalar. -void p224_base_point_mul(const u8 scalar[28], p224_point* out); - -// Multiply input point by scalar. -// out cannot point to input. -void p224_point_mul(const p224_point* input, - const u8 scalar[28], - p224_point* out); - -// Add two points. -// out cannot point to a or b. -void p224_point_add(const p224_point* a, const p224_point* b, p224_point* out); - -// Negate point. -// out cannot point to in. -void p224_point_negate(const p224_point* in, p224_point* out); - -#ifdef __cplusplus -} -#endif - -#endif // OMAHA_BASE_SECURITY_P224_H_ diff --git a/omaha/base/security/p224_ec.c b/omaha/base/security/p224_ec.c deleted file mode 100644 index 0aba16434..000000000 --- a/omaha/base/security/p224_ec.c +++ /dev/null @@ -1,850 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== -// -// After http://src.chromium.org/viewvc/chrome/trunk/src/crypto/p224.cc -// -// This is an implementation of the P224 elliptic curve group. It's written to -// be short and simple rather than fast, although it's still constant-time. -// -// WARNING: Implementing these functions in a constant-time manner far from -// obvious. Be careful when touching this code. -// Consult ise-team@ when compelled to attempt changes. -// -// See http://www.imperialviolet.org/2010/12/04/ecc.html ([1]) for background. - -#include -#include -#include - -#include "p224.h" - -typedef int32_t s32; -typedef uint64_t u64; - -// Field element functions. -// -// The field that we're dealing with is ℤ/pℤ where p = 2**224 - 2**96 + 1. -// -// Field elements are represented by a felem, which is a typedef to an -// array of 8 u32's. The value of a felem, a, is: -// a[0] + 2**28·a[1] + 2**56·a[1] + ... + 2**196·a[7] -// -// Using 28-bit limbs means that there's only 4 bits of headroom, which is less -// than we would really like. But it has the useful feature that we hit 2**224 -// exactly, making the reflections during a reduce much nicer. - -typedef u32 limb; -#define NLIMBS 8 -typedef limb felem[NLIMBS]; - -// kP is the P224 prime. -static const felem kP = { - 1, 0, 0, 268431360, - 268435455, 268435455, 268435455, 268435455, -}; - -// kB is parameter of the elliptic curve. -static const felem kB = { - 55967668, 11768882, 265861671, 185302395, - 39211076, 180311059, 84673715, 188764328, -}; - -// kBasep224_point is the base point (generator) of the elliptic curve group. -static const p224_point kBasep224_point = { - {22813985, 52956513, 34677300, 203240812, - 12143107, 133374265, 225162431, 191946955}, - {83918388, 223877528, 122119236, 123340192, - 266784067, 263504429, 146143011, 198407736}, - {1, 0, 0, 0, 0, 0, 0, 0}, -}; - -static void Contract(felem inout); - -// IsZero returns 0xffffffff if a == 0 mod p and 0 otherwise. -static u32 IsZero(const felem a) { - int i; - - felem minimal; - memcpy(minimal, a, sizeof(minimal)); - Contract(minimal); - - u32 is_zero = 0, is_p = 0; - for (i = 0; i < NLIMBS; i++) { - is_zero |= minimal[i]; - is_p |= minimal[i] - kP[i]; - } - - // If either is_zero or is_p is 0, then we should return 1. - is_zero |= is_zero >> 16; - is_zero |= is_zero >> 8; - is_zero |= is_zero >> 4; - is_zero |= is_zero >> 2; - is_zero |= is_zero >> 1; - - is_p |= is_p >> 16; - is_p |= is_p >> 8; - is_p |= is_p >> 4; - is_p |= is_p >> 2; - is_p |= is_p >> 1; - - // For is_zero and is_p, the LSB is 0 iff all the bits are zero. - is_zero &= is_p & 1; - is_zero = (~is_zero) << 31; - is_zero = (s32)(is_zero) >> 31; - return is_zero; -} - -// Add computes *out = a+b -// -// a[i] + b[i] < 2**32 -static void Add(felem out, const felem a, const felem b) { - int i; - for (i = 0; i < NLIMBS; i++) { - out[i] = a[i] + b[i]; - } -} - -#define kTwo31p3 (((u32)1)<<31) + (((u32)1)<<3) -#define kTwo31m3 (((u32)1)<<31) - (((u32)1)<<3) -#define kTwo31m15m3 (((u32)1)<<31) - (((u32)1)<<15) - (1u<<3) -// kZero31ModP is 0 mod p where bit 31 is set in all limbs so that we can -// subtract smaller amounts without underflow. See the section "Subtraction" in -// [1] for why. -static const felem kZero31ModP = { - kTwo31p3, kTwo31m3, kTwo31m3, kTwo31m15m3, - kTwo31m3, kTwo31m3, kTwo31m3, kTwo31m3 -}; - -// Subtract computes *out = a-b -// -// a[i], b[i] < 2**30 -// out[i] < 2**32 -static void Subtract(felem out, const felem a, const felem b) { - int i; - for (i = 0; i < NLIMBS; i++) { - // See the section on "Subtraction" in [1] for details. - out[i] = a[i] + kZero31ModP[i] - b[i]; - } -} - -#define kTwo63p35 (1ull<<63) + (1ull<<35) -#define kTwo63m35 (1ull<<63) - (1ull<<35) -#define kTwo63m35m19 (1ull<<63) - (1ull<<35) - (1ull<<19) -// kZero63ModP is 0 mod p where bit 63 is set in all limbs. See the section -// "Subtraction" in [1] for why. -static const u64 kZero63ModP[NLIMBS] = { - kTwo63p35, kTwo63m35, kTwo63m35, kTwo63m35, - kTwo63m35m19, kTwo63m35, kTwo63m35, kTwo63m35, -}; - -static const u32 kBottom28Bits = 0xfffffff; - -// lfelem also represents an element of the field. The limbs are -// still spaced 28-bits apart and in little-endian order. So the limbs are at -// 0, 28, 56, ..., 392 bits, each 64-bits wide. -typedef u64 lfelem[15]; - -// ReduceLarge converts a lfelem to a felem. -// -// in[i] < 2**62 -static void ReduceLarge(felem out, lfelem in) { - int i; - - for (i = 0; i < NLIMBS; i += 4) { - in[i+0] += kZero63ModP[i+0]; - in[i+1] += kZero63ModP[i+1]; - in[i+2] += kZero63ModP[i+2]; - in[i+3] += kZero63ModP[i+3]; - } - - // Eliminate the coefficients at 2**224 and greater while maintaining the - // same value mod p. - for (i = 14; i >= 8; i--) { - in[i-8] -= in[i]; // reflection off the "+1" term of p. - in[i-5] += (in[i] & 0xffff) << 12; // part of the "-2**96" reflection. - in[i-4] += in[i] >> 16; // the rest of the "-2**96" reflection. - } - in[8] = 0; - // in[0..8] < 2**64 - - // As the values become small enough, we start to store them in |out| and use - // 32-bit operations. - for (i = 1; i < 8; i++) { - in[i+1] += in[i] >> 28; - out[i] = (u32)(in[i] & kBottom28Bits); - } - // Eliminate the term at 2*224 that we introduced while keeping the same - // value mod p. - in[0] -= in[8]; // reflection off the "+1" term of p. - out[3] += (u32)(in[8] & 0xffff) << 12; // "-2**96" term - out[4] += (u32)(in[8] >> 16); // rest of "-2**96" term - // in[0] < 2**64 - // out[3] < 2**29 - // out[4] < 2**29 - // out[1,2,5..7] < 2**28 - - out[0] = (u32)(in[0] & kBottom28Bits); - out[1] += (u32)((in[0] >> 28) & kBottom28Bits); - out[2] += (u32)(in[0] >> 56); - // out[0] < 2**28 - // out[1..4] < 2**29 - // out[5..7] < 2**28 -} - -// Mul computes *out = a*b -// -// a[i] < 2**29, b[i] < 2**30 (or vice versa) -// out[i] < 2**29 -static void Mul(felem out, const felem a, const felem b) { - int i, j; - lfelem tmp = { 0 }; - - for (i = 0; i < NLIMBS; i++) { - for (j = 0; j < NLIMBS; j += 4) { - tmp[i+j+0] += (u64)(a[i]) * (u64)(b[j+0]); - tmp[i+j+1] += (u64)(a[i]) * (u64)(b[j+1]); - tmp[i+j+2] += (u64)(a[i]) * (u64)(b[j+2]); - tmp[i+j+3] += (u64)(a[i]) * (u64)(b[j+3]); - } - } - - ReduceLarge(out, tmp); -} - -// Square computes *out = a*a -// -// a[i] < 2**29 -// out[i] < 2**29 -static void Square(felem out, const felem a) { - int i, j; - lfelem tmp = { 0 }; - - tmp[0] = (u64)(a[0]) * (u64)(a[0]); - - for (i = 1; i < NLIMBS; i++) { - tmp[i] += ((u64)(a[i]) * (u64)(a[0])) << 1; - for (j = 1; j < i; j++) { - u64 r = (u64)(a[i]) * (u64)(a[j]); - tmp[i+j] += r << 1; - } - tmp[i+j] += (u64)(a[i]) * (u64)(a[j]); - } - - ReduceLarge(out, tmp); -} - -// Reduce reduces the coefficients of in_out to smaller bounds. -// -// On entry: a[i] < 2**31 + 2**30 -// On exit: a[i] < 2**29 -static void Reduce(felem a) { - int i; - - for (i = 0; i < 7; i++) { - a[i+1] += a[i] >> 28; - a[i] &= kBottom28Bits; - } - u32 top = a[7] >> 28; - a[7] &= kBottom28Bits; - - // top < 2**4 - // Constant-time: mask = (top != 0) ? 0xffffffff : 0 - u32 mask = top; - mask |= mask >> 2; - mask |= mask >> 1; - mask <<= 31; - mask = (u32)((s32)(mask) >> 31); - - // Eliminate top while maintaining the same value mod p. - a[0] -= top; - a[3] += top << 12; - - // We may have just made a[0] negative but, if we did, then we must - // have added something to a[3], thus it's > 2**12. Therefore we can - // carry down to a[0]. - a[3] -= 1 & mask; - a[2] += mask & ((((u32)1)<<28) - 1); - a[1] += mask & ((((u32)1)<<28) - 1); - a[0] += mask & (((u32)1)<<28); -} - -// Invert calcuates *out = in**-1 by computing in**(2**224 - 2**96 - 1), i.e. -// Fermat's little theorem. -static void Invert(felem out, const felem in) { - int i; - felem f1, f2, f3, f4; - - Square(f1, in); // 2 - Mul(f1, f1, in); // 2**2 - 1 - Square(f1, f1); // 2**3 - 2 - Mul(f1, f1, in); // 2**3 - 1 - Square(f2, f1); // 2**4 - 2 - Square(f2, f2); // 2**5 - 4 - Square(f2, f2); // 2**6 - 8 - Mul(f1, f1, f2); // 2**6 - 1 - Square(f2, f1); // 2**7 - 2 - for (i = 0; i < 5; i++) { // 2**12 - 2**6 - Square(f2, f2); - } - Mul(f2, f2, f1); // 2**12 - 1 - Square(f3, f2); // 2**13 - 2 - for (i = 0; i < 11; i++) { // 2**24 - 2**12 - Square(f3, f3); - } - Mul(f2, f3, f2); // 2**24 - 1 - Square(f3, f2); // 2**25 - 2 - for (i = 0; i < 23; i++) { // 2**48 - 2**24 - Square(f3, f3); - } - Mul(f3, f3, f2); // 2**48 - 1 - Square(f4, f3); // 2**49 - 2 - for (i = 0; i < 47; i++) { // 2**96 - 2**48 - Square(f4, f4); - } - Mul(f3, f3, f4); // 2**96 - 1 - Square(f4, f3); // 2**97 - 2 - for (i = 0; i < 23; i++) { // 2**120 - 2**24 - Square(f4, f4); - } - Mul(f2, f4, f2); // 2**120 - 1 - for (i = 0; i < 6; i++) { // 2**126 - 2**6 - Square(f2, f2); - } - Mul(f1, f1, f2); // 2**126 - 1 - Square(f1, f1); // 2**127 - 2 - Mul(f1, f1, in); // 2**127 - 1 - for (i = 0; i < 97; i++) { // 2**224 - 2**97 - Square(f1, f1); - } - Mul(out, f1, f3); // 2**224 - 2**96 - 1 -} - -// Contract converts a felem to its minimal, distinguished form. -// -// On entry, in[i] < 2**29 -// On exit, in[i] < 2**28 -static void Contract(felem out) { - int i; - - // Reduce the coefficients to < 2**28. - for (i = 0; i < 7; i++) { - out[i+1] += out[i] >> 28; - out[i] &= kBottom28Bits; - } - u32 top = out[7] >> 28; - out[7] &= kBottom28Bits; - - // Eliminate top while maintaining the same value mod p. - out[0] -= top; - out[3] += top << 12; - - // We may just have made out[0] negative. So we carry down. If we made - // out[0] negative then we know that out[3] is sufficiently positive - // because we just added to it. - for (i = 0; i < 3; i++) { - u32 mask = (u32)((s32)(out[i]) >> 31); - out[i] += (((u32)1) << 28) & mask; - out[i+1] -= 1 & mask; - } - - // We might have pushed out[3] over 2**28 so we perform another, partial - // carry chain-> - for (i = 3; i < 7; i++) { - out[i+1] += out[i] >> 28; - out[i] &= kBottom28Bits; - } - top = out[7] >> 28; - out[7] &= kBottom28Bits; - - // Eliminate top while maintaining the same value mod p. - out[0] -= top; - out[3] += top << 12; - - // There are two cases to consider for out[3]: - // 1) The first time that we eliminated top, we didn't push out[3] over - // 2**28. In this case, the partial carry chain didn't change any values - // and top is zero. - // 2) We did push out[3] over 2**28 the first time that we eliminated top. - // The first value of top was in [0..16), therefore, prior to eliminating - // the first top, 0xfff1000 <= out[3] <= 0xfffffff. Therefore, after - // overflowing and being reduced by the second carry chain, out[3] <= - // 0xf000. Thus it cannot have overflowed when we eliminated top for the - // second time. - - // Again, we may just have made out[0] negative, so do the same carry down. - // As before, if we made out[0] negative then we know that out[3] is - // sufficiently positive. - for (i = 0; i < 3; i++) { - u32 mask = (u32)((s32)(out[i]) >> 31); - out[i] += (((u32)1) << 28) & mask; - out[i+1] -= 1 & mask; - } - - // The value is < 2**224, but maybe greater than p. In order to reduce to a - // unique, minimal value we see if the value is >= p and, if so, subtract p. - - // First we build a mask from the top four limbs, which must all be - // equal to bottom28Bits if the whole value is >= p. If top_4_all_ones - // ends up with any zero bits in the bottom 28 bits, then this wasn't - // true. - u32 top_4_all_ones = 0xffffffffu; - for (i = 4; i < 8; i++) { - top_4_all_ones &= out[i]; - } - top_4_all_ones |= 0xf0000000; - // Now we replicate any zero bits to all the bits in top_4_all_ones. - top_4_all_ones &= top_4_all_ones >> 16; - top_4_all_ones &= top_4_all_ones >> 8; - top_4_all_ones &= top_4_all_ones >> 4; - top_4_all_ones &= top_4_all_ones >> 2; - top_4_all_ones &= top_4_all_ones >> 1; - top_4_all_ones = - (u32)((s32)(top_4_all_ones << 31) >> 31); - - // Now we test whether the bottom three limbs are non-zero. - u32 bottom_3_non_zero = out[0] | out[1] | out[2]; - bottom_3_non_zero |= bottom_3_non_zero >> 16; - bottom_3_non_zero |= bottom_3_non_zero >> 8; - bottom_3_non_zero |= bottom_3_non_zero >> 4; - bottom_3_non_zero |= bottom_3_non_zero >> 2; - bottom_3_non_zero |= bottom_3_non_zero >> 1; - bottom_3_non_zero = - (u32)((s32)(bottom_3_non_zero) >> 31); - - // Everything depends on the value of out[3]. - // If it's > 0xffff000 and top_4_all_ones != 0 then the whole value is >= p - // If it's = 0xffff000 and top_4_all_ones != 0 and bottom_3_non_zero != 0, - // then the whole value is >= p - // If it's < 0xffff000, then the whole value is < p - u32 n = out[3] - 0xffff000; - u32 out_3_equal = n; - out_3_equal |= out_3_equal >> 16; - out_3_equal |= out_3_equal >> 8; - out_3_equal |= out_3_equal >> 4; - out_3_equal |= out_3_equal >> 2; - out_3_equal |= out_3_equal >> 1; - out_3_equal = - ~(u32)((s32)(out_3_equal << 31) >> 31); - - // If out[3] > 0xffff000 then n's MSB will be zero. - u32 out_3_gt = ~(u32)((s32)(n << 31) >> 31); - - u32 mask = top_4_all_ones & ((out_3_equal & bottom_3_non_zero) | out_3_gt); - out[0] -= 1 & mask; - out[3] -= 0xffff000 & mask; - out[4] -= 0xfffffff & mask; - out[5] -= 0xfffffff & mask; - out[6] -= 0xfffffff & mask; - out[7] -= 0xfffffff & mask; -} - - -// Group element functions. -// -// These functions deal with group elements. The group is an elliptic curve -// group with a = -3 defined in FIPS 186-3, section D.2.2. - -static void CopyConditional(p224_point* out, const p224_point* a, u32 mask); -static void DoubleJacobian(p224_point* out, const p224_point* a); - -// AddJacobian computes *out = a+b where a != b-> -static void AddJacobian(p224_point *out, - const p224_point* a, - const p224_point* b) { - // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl - int n; - felem z1z1, z2z2, u1, u2, s1, s2, h, i, j, r, v; - - u32 z1_is_zero = IsZero(a->z); - u32 z2_is_zero = IsZero(b->z); - - // Z1Z1 = Z1² - Square(z1z1, a->z); - - // Z2Z2 = Z2² - Square(z2z2, b->z); - - // U1 = X1*Z2Z2 - Mul(u1, a->x, z2z2); - - // U2 = X2*Z1Z1 - Mul(u2, b->x, z1z1); - - // S1 = Y1*Z2*Z2Z2 - Mul(s1, b->z, z2z2); - Mul(s1, a->y, s1); - - // S2 = Y2*Z1*Z1Z1 - Mul(s2, a->z, z1z1); - Mul(s2, b->y, s2); - - // H = U2-U1 - Subtract(h, u2, u1); - Reduce(h); - u32 x_equal = IsZero(h); - - // I = (2*H)² - for (n = 0; n < NLIMBS; n++) { - i[n] = h[n] << 1; - } - Reduce(i); - Square(i, i); - - // J = H*I - Mul(j, h, i); - // r = 2*(S2-S1) - Subtract(r, s2, s1); - Reduce(r); - - u32 y_equal = IsZero(r); - - // All variables we test here are output from IsZero(), thus either 0 or -1. - // We use a fixed timing evaluation of the total expression. - // The if() body never gets executed during private scalar multiplies, - // (e.g. ScalarMult()) but might trigger during public ecdsa verify computation. - if (x_equal & y_equal & ~z1_is_zero & ~z2_is_zero) { - // The two input points are the same (and finite), - // therefore we must use the dedicated doubling function - // as the slope of the line is undefined. - DoubleJacobian(out, a); - return; - } - - for (n = 0; n < NLIMBS; n++) { - r[n] <<= 1; - } - Reduce(r); - - // V = U1*I - Mul(v, u1, i); - - // Z3 = ((Z1+Z2)²-Z1Z1-Z2Z2)*H - Add(z1z1, z1z1, z2z2); - Add(z2z2, a->z, b->z); - Reduce(z2z2); - Square(z2z2, z2z2); - Subtract(out->z, z2z2, z1z1); - Reduce(out->z); - Mul(out->z, out->z, h); - - // X3 = r²-J-2*V - for (n = 0; n < NLIMBS; n++) { - z1z1[n] = v[n] << 1; - } - Add(z1z1, j, z1z1); - Reduce(z1z1); - Square(out->x, r); - Subtract(out->x, out->x, z1z1); - Reduce(out->x); - - // Y3 = r*(V-X3)-2*S1*J - for (n = 0; n < NLIMBS; n++) { - s1[n] <<= 1; - } - Mul(s1, s1, j); - Subtract(z1z1, v, out->x); - Reduce(z1z1); - Mul(z1z1, z1z1, r); - Subtract(out->y, z1z1, s1); - Reduce(out->y); - - CopyConditional(out, a, z2_is_zero); - CopyConditional(out, b, z1_is_zero); -} - -// DoubleJacobian computes *out = a+a-> -static void DoubleJacobian(p224_point* out, const p224_point* a) { - // See http://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b - int i; - felem delta, gamma, beta, alpha, t; - - Square(delta, a->z); - Square(gamma, a->y); - Mul(beta, a->x, gamma); - - // alpha = 3*(X1-delta)*(X1+delta) - Add(t, a->x, delta); - for (i = 0; i < NLIMBS; i++) { - t[i] += t[i] << 1; - } - Reduce(t); - Subtract(alpha, a->x, delta); - Reduce(alpha); - Mul(alpha, alpha, t); - - // Z3 = (Y1+Z1)²-gamma-delta - Add(out->z, a->y, a->z); - Reduce(out->z); - Square(out->z, out->z); - Subtract(out->z, out->z, gamma); - Reduce(out->z); - Subtract(out->z, out->z, delta); - Reduce(out->z); - - // X3 = alpha²-8*beta - for (i = 0; i < NLIMBS; i++) { - delta[i] = beta[i] << 3; - } - Reduce(delta); - Square(out->x, alpha); - Subtract(out->x, out->x, delta); - Reduce(out->x); - - // Y3 = alpha*(4*beta-X3)-8*gamma² - for (i = 0; i < NLIMBS; i++) { - beta[i] <<= 2; - } - Reduce(beta); - Subtract(beta, beta, out->x); - Reduce(beta); - Square(gamma, gamma); - for (i = 0; i < NLIMBS; i++) { - gamma[i] <<= 3; - } - Reduce(gamma); - Mul(out->y, alpha, beta); - Subtract(out->y, out->y, gamma); - Reduce(out->y); -} - -// CopyConditional sets *out=a if mask is 0xffffffff. mask must be either 0 or -// 0xffffffff. -static void CopyConditional(p224_point* out, - const p224_point* a, - u32 mask) { - int i; - for (i = 0; i < NLIMBS; i++) { - out->x[i] ^= mask & (a->x[i] ^ out->x[i]); - out->y[i] ^= mask & (a->y[i] ^ out->y[i]); - out->z[i] ^= mask & (a->z[i] ^ out->z[i]); - } -} - -// NON_ZERO_TO_ALL_ONES returns: -// 0xffffffff for 0 < x <= 2**31 -// 0 for x == 0 or x > 2**31. -// -// This macro assumes that right-shifting a signed number shifts in the MSB on -// the left. This is not ensured by the C standard, but is true on the CPUs -// that we're targetting with this code (x86 and ARM). -#define NON_ZERO_TO_ALL_ONES(x) (~((u32) (((s32) ((x)-1)) >> 31))) - -// Select table entry at index. -// Access all entries in table in a fixed-timing manner. -static void SelectJacobian(const p224_point table[16], - u32 index, - p224_point* out) { - int i; - memset(out, 0, sizeof(*out)); - for (i = 1; i < 16; ++i) { - CopyConditional(out, &table[i], ~NON_ZERO_TO_ALL_ONES(i ^ index)); - } -} - -// ScalarMult calculates *out = a*scalar where scalar is a big-endian number of -// length scalar_len and != 0. -static void ScalarMult(p224_point* out, - const p224_point* a, - const u8* scalar, - int scalar_len) { - p224_point tbl[16], tmp; - u32 out_is_infinity_mask, tmp_is_noninfinite_mask, mask; - int i; - - memset(out, 0, sizeof(*out)); - tbl[0] = *out; - tbl[1] = *a; - for (i = 2; i < 16; i += 2) { - DoubleJacobian(&tbl[i], &tbl[i / 2]); - AddJacobian(&tbl[i + 1], &tbl[i], a); - } - out_is_infinity_mask = -1; - - for (i = 0; i < scalar_len; i++) { - u32 idx; - - if (i) { - DoubleJacobian(out, out); - DoubleJacobian(out, out); - DoubleJacobian(out, out); - DoubleJacobian(out, out); - } - - idx = (scalar[i] >> 4) & 15; - SelectJacobian(tbl, idx, &tmp); - AddJacobian(&tbl[0], &tmp, out); - CopyConditional(out, &tmp, out_is_infinity_mask); - - tmp_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(idx); - mask = tmp_is_noninfinite_mask & ~out_is_infinity_mask; - - CopyConditional(out, &tbl[0], mask); - - out_is_infinity_mask &= ~tmp_is_noninfinite_mask; - - DoubleJacobian(out, out); - DoubleJacobian(out, out); - DoubleJacobian(out, out); - DoubleJacobian(out, out); - - idx = scalar[i] & 15; - SelectJacobian(tbl, idx, &tmp); - AddJacobian(&tbl[0], &tmp, out); - CopyConditional(out, &tmp, out_is_infinity_mask); - - tmp_is_noninfinite_mask = NON_ZERO_TO_ALL_ONES(idx); - mask = tmp_is_noninfinite_mask & ~out_is_infinity_mask; - - CopyConditional(out, &tbl[0], mask); - - out_is_infinity_mask &= ~tmp_is_noninfinite_mask; - } -} - -static u32 u32_from_bin(const u8* v) { - return (((u32)v[0]) << 24) | - (((u32)v[1]) << 16) | - (v[2] << 8) | - v[3]; -} - -static void u32_to_bin(u8* p, u32 v) { - p[0] = v >> 24; - p[1] = v >> 16; - p[2] = v >> 8; - p[3] = v; -} - -// Get224Bits reads 7 words from in and scatters their contents in -// little-endian form into 8 words at out, 28 bits per output word. -static void Get224Bits(felem out, const u8* in) { - out[0] = u32_from_bin(&in[4*6]) & kBottom28Bits; - out[1] = ((u32_from_bin(&in[4*5]) << 4) | - (u32_from_bin(&in[4*6]) >> 28)) & kBottom28Bits; - out[2] = ((u32_from_bin(&in[4*4]) << 8) | - (u32_from_bin(&in[4*5]) >> 24)) & kBottom28Bits; - out[3] = ((u32_from_bin(&in[4*3]) << 12) | - (u32_from_bin(&in[4*4]) >> 20)) & kBottom28Bits; - out[4] = ((u32_from_bin(&in[4*2]) << 16) | - (u32_from_bin(&in[4*3]) >> 16)) & kBottom28Bits; - out[5] = ((u32_from_bin(&in[4*1]) << 20) | - (u32_from_bin(&in[4*2]) >> 12)) & kBottom28Bits; - out[6] = ((u32_from_bin(&in[4*0]) << 24) | - (u32_from_bin(&in[4*1]) >> 8)) & kBottom28Bits; - out[7] = (u32_from_bin(&in[4*0]) >> 4) & kBottom28Bits; -} - -// Put224Bits performs the inverse operation to Get224Bits: taking 28 bits from -// each of 8 input words and writing them in big-endian order to 7 words at -// out. -static void Put224Bits(u8* out, const felem in) { - u32_to_bin(&out[4*6], (in[0] >> 0) | (in[1] << 28)); - u32_to_bin(&out[4*5], (in[1] >> 4) | (in[2] << 24)); - u32_to_bin(&out[4*4], (in[2] >> 8) | (in[3] << 20)); - u32_to_bin(&out[4*3], (in[3] >> 12) | (in[4] << 16)); - u32_to_bin(&out[4*2], (in[4] >> 16) | (in[5] << 12)); - u32_to_bin(&out[4*1], (in[5] >> 20) | (in[6] << 8)); - u32_to_bin(&out[4*0], (in[6] >> 24) | (in[7] << 4)); -} - -// Public API functions. - -int p224_point_from_bin(const void* in, int size, p224_point* out) { - int i; - if (size != 56) return 0; - - const u8* inbytes = (const u8*)(in); - Get224Bits(out->x, inbytes); - Get224Bits(out->y, inbytes + 28); - - memset(out->z, 0, sizeof(out->z)); - out->z[0] = 1; - - // Check that the point is on the curve, i.e. that y² = x³ - 3x + b - felem lhs; - Square(lhs, out->y); - Contract(lhs); - - felem rhs; - Square(rhs, out->x); - Mul(rhs, out->x, rhs); - - felem three_x; - for (i = 0; i < 8; i++) { - three_x[i] = out->x[i] * 3; - } - Reduce(three_x); - Subtract(rhs, rhs, three_x); - Reduce(rhs); - - Add(rhs, rhs, kB); - Contract(rhs); - return memcmp(lhs, rhs, sizeof(lhs)) == 0; -} - -void p224_point_to_bin(const p224_point* in, void* out) { - felem zinv, zinv_sq, x, y; - - // If this is the point at infinity we return a string of all zeros. - if (IsZero(in->z)) { - memset(out, 0, 56); - return; - } - - Invert(zinv, in->z); - Square(zinv_sq, zinv); - Mul(x, in->x, zinv_sq); - Mul(zinv_sq, zinv_sq, zinv); - Mul(y, in->y, zinv_sq); - - Contract(x); - Contract(y); - - u8* outbytes = (u8*)out; - Put224Bits(outbytes, x); - Put224Bits(outbytes + 28, y); -} - -void p224_point_mul(const p224_point* in, - const u8 scalar[28], - p224_point* out) { - ScalarMult(out, in, scalar, 28); -} - -void p224_base_point_mul(const u8 scalar[28], p224_point* out) { - ScalarMult(out, &kBasep224_point, scalar, 28); -} - -void p224_point_add(const p224_point* a, const p224_point* b, p224_point* out) { - AddJacobian(out, a, b); -} - -void p224_point_negate(const p224_point* in, p224_point* out) { - // Guide to elliptic curve cryptography, page 89 suggests that (X : X+Y : Z) - // is the negative in Jacobian coordinates, but it doesn't actually appear to - // be true in testing so this performs the negation in affine coordinates. - felem zinv, zinv_sq, y; - Invert(zinv, in->z); - Square(zinv_sq, zinv); - Mul(out->x, in->x, zinv_sq); - Mul(zinv_sq, zinv_sq, zinv); - Mul(y, in->y, zinv_sq); - - Subtract(out->y, kP, y); - Reduce(out->y); - - memset(out->z, 0, sizeof(out->z)); - out->z[0] = 1; -} diff --git a/omaha/base/security/p224_ec_unittest.c b/omaha/base/security/p224_ec_unittest.c deleted file mode 100644 index 0041e478d..000000000 --- a/omaha/base/security/p224_ec_unittest.c +++ /dev/null @@ -1,814 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#include -#include -#include -#include - -#include "p224.h" - -// kBasePointExternal is the P224 base point in external representation. -static const uint8_t kBasePointExternal[56] = { - 0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, - 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, - 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, - 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, - 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, - 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, - 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34, -}; - -// TestVector represents a test of scalar multiplication of the base point. -// |scalar| is a big-endian scalar and |affine| is the external representation -// of g*scalar. -struct TestVector { - uint8_t scalar[28]; - uint8_t affine[28*2]; -}; - -#define kNumNISTTestVectors 52 - -// kNISTTestVectors are the NIST test vectors for P224. -static const struct TestVector kNISTTestVectors[kNumNISTTestVectors] = { - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01}, - {0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, - 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, - 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, - 0x11, 0x5c, 0x1d, 0x21, 0xbd, 0x37, 0x63, 0x88, - 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, - 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x07, 0x47, 0x64, - 0x44, 0xd5, 0x81, 0x99, 0x85, 0x00, 0x7e, 0x34 - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, }, - - {0x70, 0x6a, 0x46, 0xdc, 0x76, 0xdc, 0xb7, 0x67, - 0x98, 0xe6, 0x0e, 0x6d, 0x89, 0x47, 0x47, 0x88, - 0xd1, 0x6d, 0xc1, 0x80, 0x32, 0xd2, 0x68, 0xfd, - 0x1a, 0x70, 0x4f, 0xa6, 0x1c, 0x2b, 0x76, 0xa7, - 0xbc, 0x25, 0xe7, 0x70, 0x2a, 0x70, 0x4f, 0xa9, - 0x86, 0x89, 0x28, 0x49, 0xfc, 0xa6, 0x29, 0x48, - 0x7a, 0xcf, 0x37, 0x09, 0xd2, 0xe4, 0xe8, 0xbb, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x03, }, - {0xdf, 0x1b, 0x1d, 0x66, 0xa5, 0x51, 0xd0, 0xd3, - 0x1e, 0xff, 0x82, 0x25, 0x58, 0xb9, 0xd2, 0xcc, - 0x75, 0xc2, 0x18, 0x02, 0x79, 0xfe, 0x0d, 0x08, - 0xfd, 0x89, 0x6d, 0x04, 0xa3, 0xf7, 0xf0, 0x3c, - 0xad, 0xd0, 0xbe, 0x44, 0x4c, 0x0a, 0xa5, 0x68, - 0x30, 0x13, 0x0d, 0xdf, 0x77, 0xd3, 0x17, 0x34, - 0x4e, 0x1a, 0xf3, 0x59, 0x19, 0x81, 0xa9, 0x25, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x04, }, - {0xae, 0x99, 0xfe, 0xeb, 0xb5, 0xd2, 0x69, 0x45, - 0xb5, 0x48, 0x92, 0x09, 0x2a, 0x8a, 0xee, 0x02, - 0x91, 0x29, 0x30, 0xfa, 0x41, 0xcd, 0x11, 0x4e, - 0x40, 0x44, 0x73, 0x01, 0x04, 0x82, 0x58, 0x0a, - 0x0e, 0xc5, 0xbc, 0x47, 0xe8, 0x8b, 0xc8, 0xc3, - 0x78, 0x63, 0x2c, 0xd1, 0x96, 0xcb, 0x3f, 0xa0, - 0x58, 0xa7, 0x11, 0x4e, 0xb0, 0x30, 0x54, 0xc9, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x05, }, - {0x31, 0xc4, 0x9a, 0xe7, 0x5b, 0xce, 0x78, 0x07, - 0xcd, 0xff, 0x22, 0x05, 0x5d, 0x94, 0xee, 0x90, - 0x21, 0xfe, 0xdb, 0xb5, 0xab, 0x51, 0xc5, 0x75, - 0x26, 0xf0, 0x11, 0xaa, 0x27, 0xe8, 0xbf, 0xf1, - 0x74, 0x56, 0x35, 0xec, 0x5b, 0xa0, 0xc9, 0xf1, - 0xc2, 0xed, 0xe1, 0x54, 0x14, 0xc6, 0x50, 0x7d, - 0x29, 0xff, 0xe3, 0x7e, 0x79, 0x0a, 0x07, 0x9b, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x06, }, - {0x1f, 0x24, 0x83, 0xf8, 0x25, 0x72, 0x25, 0x1f, - 0xca, 0x97, 0x5f, 0xea, 0x40, 0xdb, 0x82, 0x1d, - 0xf8, 0xad, 0x82, 0xa3, 0xc0, 0x02, 0xee, 0x6c, - 0x57, 0x11, 0x24, 0x08, 0x89, 0xfa, 0xf0, 0xcc, - 0xb7, 0x50, 0xd9, 0x9b, 0x55, 0x3c, 0x57, 0x4f, - 0xad, 0x7e, 0xcf, 0xb0, 0x43, 0x85, 0x86, 0xeb, - 0x39, 0x52, 0xaf, 0x5b, 0x4b, 0x15, 0x3c, 0x7e, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x07, }, - {0xdb, 0x2f, 0x6b, 0xe6, 0x30, 0xe2, 0x46, 0xa5, - 0xcf, 0x7d, 0x99, 0xb8, 0x51, 0x94, 0xb1, 0x23, - 0xd4, 0x87, 0xe2, 0xd4, 0x66, 0xb9, 0x4b, 0x24, - 0xa0, 0x3c, 0x3e, 0x28, 0x0f, 0x3a, 0x30, 0x08, - 0x54, 0x97, 0xf2, 0xf6, 0x11, 0xee, 0x25, 0x17, - 0xb1, 0x63, 0xef, 0x8c, 0x53, 0xb7, 0x15, 0xd1, - 0x8b, 0xb4, 0xe4, 0x80, 0x8d, 0x02, 0xb9, 0x63, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x08, }, - {0x85, 0x8e, 0x6f, 0x9c, 0xc6, 0xc1, 0x2c, 0x31, - 0xf5, 0xdf, 0x12, 0x4a, 0xa7, 0x77, 0x67, 0xb0, - 0x5c, 0x8b, 0xc0, 0x21, 0xbd, 0x68, 0x3d, 0x2b, - 0x55, 0x57, 0x15, 0x50, 0x04, 0x6d, 0xcd, 0x3e, - 0xa5, 0xc4, 0x38, 0x98, 0xc5, 0xc5, 0xfc, 0x4f, - 0xda, 0xc7, 0xdb, 0x39, 0xc2, 0xf0, 0x2e, 0xbe, - 0xe4, 0xe3, 0x54, 0x1d, 0x1e, 0x78, 0x04, 0x7a, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x09, }, - {0x2f, 0xdc, 0xcc, 0xfe, 0xe7, 0x20, 0xa7, 0x7e, - 0xf6, 0xcb, 0x3b, 0xfb, 0xb4, 0x47, 0xf9, 0x38, - 0x31, 0x17, 0xe3, 0xda, 0xa4, 0xa0, 0x7e, 0x36, - 0xed, 0x15, 0xf7, 0x8d, 0x37, 0x17, 0x32, 0xe4, - 0xf4, 0x1b, 0xf4, 0xf7, 0x88, 0x30, 0x35, 0xe6, - 0xa7, 0x9f, 0xce, 0xdc, 0x0e, 0x19, 0x6e, 0xb0, - 0x7b, 0x48, 0x17, 0x16, 0x97, 0x51, 0x74, 0x63, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0a, }, - {0xae, 0xa9, 0xe1, 0x7a, 0x30, 0x65, 0x17, 0xeb, - 0x89, 0x15, 0x2a, 0xa7, 0x09, 0x6d, 0x2c, 0x38, - 0x1e, 0xc8, 0x13, 0xc5, 0x1a, 0xa8, 0x80, 0xe7, - 0xbe, 0xe2, 0xc0, 0xfd, 0x39, 0xbb, 0x30, 0xea, - 0xb3, 0x37, 0xe0, 0xa5, 0x21, 0xb6, 0xcb, 0xa1, - 0xab, 0xe4, 0xb2, 0xb3, 0xa3, 0xe5, 0x24, 0xc1, - 0x4a, 0x3f, 0xe3, 0xeb, 0x11, 0x6b, 0x65, 0x5f, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0b, }, - {0xef, 0x53, 0xb6, 0x29, 0x4a, 0xca, 0x43, 0x1f, - 0x0f, 0x3c, 0x22, 0xdc, 0x82, 0xeb, 0x90, 0x50, - 0x32, 0x4f, 0x1d, 0x88, 0xd3, 0x77, 0xe7, 0x16, - 0x44, 0x8e, 0x50, 0x7c, 0x20, 0xb5, 0x10, 0x00, - 0x40, 0x92, 0xe9, 0x66, 0x36, 0xcf, 0xb7, 0xe3, - 0x2e, 0xfd, 0xed, 0x82, 0x65, 0xc2, 0x66, 0xdf, - 0xb7, 0x54, 0xfa, 0x6d, 0x64, 0x91, 0xa6, 0xda, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0c, }, - {0x6e, 0x31, 0xee, 0x1d, 0xc1, 0x37, 0xf8, 0x1b, - 0x05, 0x67, 0x52, 0xe4, 0xde, 0xab, 0x14, 0x43, - 0xa4, 0x81, 0x03, 0x3e, 0x9b, 0x4c, 0x93, 0xa3, - 0x04, 0x4f, 0x4f, 0x7a, 0x20, 0x7d, 0xdd, 0xf0, - 0x38, 0x5b, 0xfd, 0xea, 0xb6, 0xe9, 0xac, 0xda, - 0x8d, 0xa0, 0x6b, 0x3b, 0xbe, 0xf2, 0x24, 0xa9, - 0x3a, 0xb1, 0xe9, 0xe0, 0x36, 0x10, 0x9d, 0x13, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0d, }, - {0x34, 0xe8, 0xe1, 0x7a, 0x43, 0x0e, 0x43, 0x28, - 0x97, 0x93, 0xc3, 0x83, 0xfa, 0xc9, 0x77, 0x42, - 0x47, 0xb4, 0x0e, 0x9e, 0xbd, 0x33, 0x66, 0x98, - 0x1f, 0xcf, 0xae, 0xca, 0x25, 0x28, 0x19, 0xf7, - 0x1c, 0x7f, 0xb7, 0xfb, 0xcb, 0x15, 0x9b, 0xe3, - 0x37, 0xd3, 0x7d, 0x33, 0x36, 0xd7, 0xfe, 0xb9, - 0x63, 0x72, 0x4f, 0xdf, 0xb0, 0xec, 0xb7, 0x67, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0e, }, - {0xa5, 0x36, 0x40, 0xc8, 0x3d, 0xc2, 0x08, 0x60, - 0x3d, 0xed, 0x83, 0xe4, 0xec, 0xf7, 0x58, 0xf2, - 0x4c, 0x35, 0x7d, 0x7c, 0xf4, 0x80, 0x88, 0xb2, - 0xce, 0x01, 0xe9, 0xfa, 0xd5, 0x81, 0x4c, 0xd7, - 0x24, 0x19, 0x9c, 0x4a, 0x5b, 0x97, 0x4a, 0x43, - 0x68, 0x5f, 0xbf, 0x5b, 0x8b, 0xac, 0x69, 0x45, - 0x9c, 0x94, 0x69, 0xbc, 0x8f, 0x23, 0xcc, 0xaf, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x0f, }, - {0xba, 0xa4, 0xd8, 0x63, 0x55, 0x11, 0xa7, 0xd2, - 0x88, 0xae, 0xbe, 0xed, 0xd1, 0x2c, 0xe5, 0x29, - 0xff, 0x10, 0x2c, 0x91, 0xf9, 0x7f, 0x86, 0x7e, - 0x21, 0x91, 0x6b, 0xf9, 0x97, 0x9a, 0x5f, 0x47, - 0x59, 0xf8, 0x0f, 0x4f, 0xb4, 0xec, 0x2e, 0x34, - 0xf5, 0x56, 0x6d, 0x59, 0x56, 0x80, 0xa1, 0x17, - 0x35, 0xe7, 0xb6, 0x10, 0x46, 0x12, 0x79, 0x89, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x10, }, - {0x0b, 0x6e, 0xc4, 0xfe, 0x17, 0x77, 0x38, 0x24, - 0x04, 0xef, 0x67, 0x99, 0x97, 0xba, 0x8d, 0x1c, - 0xc5, 0xcd, 0x8e, 0x85, 0x34, 0x92, 0x59, 0xf5, - 0x90, 0xc4, 0xc6, 0x6d, 0x33, 0x99, 0xd4, 0x64, - 0x34, 0x59, 0x06, 0xb1, 0x1b, 0x00, 0xe3, 0x63, - 0xef, 0x42, 0x92, 0x21, 0xf2, 0xec, 0x72, 0x0d, - 0x2f, 0x66, 0x5d, 0x7d, 0xea, 0xd5, 0xb4, 0x82, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x11, }, - {0xb8, 0x35, 0x7c, 0x3a, 0x6c, 0xee, 0xf2, 0x88, - 0x31, 0x0e, 0x17, 0xb8, 0xbf, 0xef, 0xf9, 0x20, - 0x08, 0x46, 0xca, 0x8c, 0x19, 0x42, 0x49, 0x7c, - 0x48, 0x44, 0x03, 0xbc, 0xff, 0x14, 0x9e, 0xfa, - 0x66, 0x06, 0xa6, 0xbd, 0x20, 0xef, 0x7d, 0x1b, - 0x06, 0xbd, 0x92, 0xf6, 0x90, 0x46, 0x39, 0xdc, - 0xe5, 0x17, 0x4d, 0xb6, 0xcc, 0x55, 0x4a, 0x26, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x12, }, - {0xc9, 0xff, 0x61, 0xb0, 0x40, 0x87, 0x4c, 0x05, - 0x68, 0x47, 0x92, 0x16, 0x82, 0x4a, 0x15, 0xea, - 0xb1, 0xa8, 0x38, 0xa7, 0x97, 0xd1, 0x89, 0x74, - 0x62, 0x26, 0xe4, 0xcc, 0xea, 0x98, 0xd6, 0x0e, - 0x5f, 0xfc, 0x9b, 0x8f, 0xcf, 0x99, 0x9f, 0xab, - 0x1d, 0xf7, 0xe7, 0xef, 0x70, 0x84, 0xf2, 0x0d, - 0xdb, 0x61, 0xbb, 0x04, 0x5a, 0x6c, 0xe0, 0x02, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x13, }, - {0xa1, 0xe8, 0x1c, 0x04, 0xf3, 0x0c, 0xe2, 0x01, - 0xc7, 0xc9, 0xac, 0xe7, 0x85, 0xed, 0x44, 0xcc, - 0x33, 0xb4, 0x55, 0xa0, 0x22, 0xf2, 0xac, 0xdb, - 0xc6, 0xca, 0xe8, 0x3c, 0xdc, 0xf1, 0xf6, 0xc3, - 0xdb, 0x09, 0xc7, 0x0a, 0xcc, 0x25, 0x39, 0x1d, - 0x49, 0x2f, 0xe2, 0x5b, 0x4a, 0x18, 0x0b, 0xab, - 0xd6, 0xce, 0xa3, 0x56, 0xc0, 0x47, 0x19, 0xcd, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x14, }, - {0xfc, 0xc7, 0xf2, 0xb4, 0x5d, 0xf1, 0xcd, 0x5a, - 0x3c, 0x0c, 0x07, 0x31, 0xca, 0x47, 0xa8, 0xaf, - 0x75, 0xcf, 0xb0, 0x34, 0x7e, 0x83, 0x54, 0xee, - 0xfe, 0x78, 0x24, 0x55, 0x0d, 0x5d, 0x71, 0x10, - 0x27, 0x4c, 0xba, 0x7c, 0xde, 0xe9, 0x0e, 0x1a, - 0x8b, 0x0d, 0x39, 0x4c, 0x37, 0x6a, 0x55, 0x73, - 0xdb, 0x6b, 0xe0, 0xbf, 0x27, 0x47, 0xf5, 0x30, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x01, 0x8e, 0xbb, 0xb9, - 0x5e, 0xed, 0x0e, 0x13, }, - {0x61, 0xf0, 0x77, 0xc6, 0xf6, 0x2e, 0xd8, 0x02, - 0xda, 0xd7, 0xc2, 0xf3, 0x8f, 0x5c, 0x67, 0xf2, - 0xcc, 0x45, 0x36, 0x01, 0xe6, 0x1b, 0xd0, 0x76, - 0xbb, 0x46, 0x17, 0x9e, 0x22, 0x72, 0xf9, 0xe9, - 0xf5, 0x93, 0x3e, 0x70, 0x38, 0x8e, 0xe6, 0x52, - 0x51, 0x34, 0x43, 0xb5, 0xe2, 0x89, 0xdd, 0x13, - 0x5d, 0xcc, 0x0d, 0x02, 0x99, 0xb2, 0x25, 0xe4, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x15, 0x9d, 0x89, - 0x3d, 0x4c, 0xdd, 0x74, 0x72, 0x46, 0xcd, 0xca, - 0x43, 0x59, 0x0e, 0x13, }, - {0x02, 0x98, 0x95, 0xf0, 0xaf, 0x49, 0x6b, 0xfc, - 0x62, 0xb6, 0xef, 0x8d, 0x8a, 0x65, 0xc8, 0x8c, - 0x61, 0x39, 0x49, 0xb0, 0x36, 0x68, 0xaa, 0xb4, - 0xf0, 0x42, 0x9e, 0x35, 0x3e, 0xa6, 0xe5, 0x3f, - 0x9a, 0x84, 0x1f, 0x20, 0x19, 0xec, 0x24, 0xbd, - 0xe1, 0xa7, 0x56, 0x77, 0xaa, 0x9b, 0x59, 0x02, - 0xe6, 0x10, 0x81, 0xc0, 0x10, 0x64, 0xde, 0x93, - }, - }, - { - {0x41, 0xff, 0xc1, 0xff, 0xff, 0xfe, 0x01, 0xff, - 0xfc, 0x00, 0x03, 0xff, 0xfe, 0x00, 0x07, 0xc0, - 0x01, 0xff, 0xf0, 0x00, 0x03, 0xff, 0xf0, 0x7f, - 0xfe, 0x00, 0x07, 0xc0, }, - {0xab, 0x68, 0x99, 0x30, 0xbc, 0xae, 0x4a, 0x4a, - 0xa5, 0xf5, 0xcb, 0x08, 0x5e, 0x82, 0x3e, 0x8a, - 0xe3, 0x0f, 0xd3, 0x65, 0xeb, 0x1d, 0xa4, 0xab, - 0xa9, 0xcf, 0x03, 0x79, 0x33, 0x45, 0xa1, 0x21, - 0xbb, 0xd2, 0x33, 0x54, 0x8a, 0xf0, 0xd2, 0x10, - 0x65, 0x4e, 0xb4, 0x0b, 0xab, 0x78, 0x8a, 0x03, - 0x66, 0x64, 0x19, 0xbe, 0x6f, 0xbd, 0x34, 0xe7, - }, - }, - { - {0x7f, 0xff, 0xff, 0xc0, 0x3f, 0xff, 0xc0, 0x03, - 0xff, 0xff, 0xfc, 0x00, 0x7f, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x07, 0x00, 0x00, 0x10, 0x00, 0x00, - 0x00, 0x0e, 0x00, 0xff, }, - {0xbd, 0xb6, 0xa8, 0x81, 0x7c, 0x1f, 0x89, 0xda, - 0x1c, 0x2f, 0x3d, 0xd8, 0xe9, 0x7f, 0xeb, 0x44, - 0x94, 0xf2, 0xed, 0x30, 0x2a, 0x4c, 0xe2, 0xbc, - 0x7f, 0x5f, 0x40, 0x25, 0x4c, 0x70, 0x20, 0xd5, - 0x7c, 0x00, 0x41, 0x18, 0x89, 0x46, 0x2d, 0x77, - 0xa5, 0x43, 0x8b, 0xb4, 0xe9, 0x7d, 0x17, 0x77, - 0x00, 0xbf, 0x72, 0x43, 0xa0, 0x7f, 0x16, 0x80, - }, - }, - { - {0x7f, 0xff, 0xff, 0x04, 0x00, 0x00, 0x00, 0x00, - 0xff, 0xff, 0xf0, 0x1f, 0xff, 0xf8, 0xff, 0xff, - 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x00, - 0x00, 0x0f, 0xff, 0xff, }, - {0xd5, 0x8b, 0x61, 0xaa, 0x41, 0xc3, 0x2d, 0xd5, - 0xeb, 0xa4, 0x62, 0x64, 0x7d, 0xba, 0x75, 0xc5, - 0xd6, 0x7c, 0x83, 0x60, 0x6c, 0x0a, 0xf2, 0xbd, - 0x92, 0x84, 0x46, 0xa9, 0xd2, 0x4b, 0xa6, 0xa8, - 0x37, 0xbe, 0x04, 0x60, 0xdd, 0x10, 0x7a, 0xe7, - 0x77, 0x25, 0x69, 0x6d, 0x21, 0x14, 0x46, 0xc5, - 0x60, 0x9b, 0x45, 0x95, 0x97, 0x6b, 0x16, 0xbd, - }, - }, - { - {0x7f, 0xff, 0xff, 0xc0, 0x00, 0xff, 0xfe, 0x3f, - 0xff, 0xfc, 0x10, 0x00, 0x00, 0x20, 0x00, 0x3f, - 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, - 0x3f, 0xff, 0xff, 0xff, }, - {0xdc, 0x9f, 0xa7, 0x79, 0x78, 0xa0, 0x05, 0x51, - 0x09, 0x80, 0xe9, 0x29, 0xa1, 0x48, 0x5f, 0x63, - 0x71, 0x6d, 0xf6, 0x95, 0xd7, 0xa0, 0xc1, 0x8b, - 0xb5, 0x18, 0xdf, 0x03, 0xed, 0xe2, 0xb0, 0x16, - 0xf2, 0xdd, 0xff, 0xc2, 0xa8, 0xc0, 0x15, 0xb1, - 0x34, 0x92, 0x82, 0x75, 0xce, 0x09, 0xe5, 0x66, - 0x1b, 0x7a, 0xb1, 0x4c, 0xe0, 0xd1, 0xd4, 0x03, - }, - }, - { - {0x70, 0x01, 0xf0, 0x00, 0x1c, 0x00, 0x01, 0xc0, - 0x00, 0x00, 0x1f, 0xff, 0xff, 0xfc, 0x00, 0x00, - 0x1f, 0xff, 0xff, 0xf8, 0x00, 0x0f, 0xc0, 0x00, - 0x00, 0x01, 0xfc, 0x00, }, - {0x49, 0x9d, 0x8b, 0x28, 0x29, 0xcf, 0xb8, 0x79, - 0xc9, 0x01, 0xf7, 0xd8, 0x5d, 0x35, 0x70, 0x45, - 0xed, 0xab, 0x55, 0x02, 0x88, 0x24, 0xd0, 0xf0, - 0x5b, 0xa2, 0x79, 0xba, 0xbf, 0x92, 0x95, 0x37, - 0xb0, 0x6e, 0x40, 0x15, 0x91, 0x96, 0x39, 0xd9, - 0x4f, 0x57, 0x83, 0x8f, 0xa3, 0x3f, 0xc3, 0xd9, - 0x52, 0x59, 0x8d, 0xcd, 0xbb, 0x44, 0xd6, 0x38, - }, - }, - { - {0x00, 0x00, 0x00, 0x00, 0x1f, 0xfc, 0x00, 0x00, - 0x00, 0xff, 0xf0, 0x30, 0x00, 0x1f, 0x00, 0x00, - 0xff, 0xff, 0xf0, 0x00, 0x00, 0x38, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x02, }, - {0x82, 0x46, 0xc9, 0x99, 0x13, 0x71, 0x86, 0x63, - 0x2c, 0x5f, 0x9e, 0xdd, 0xf3, 0xb1, 0xb0, 0xe1, - 0x76, 0x4c, 0x5e, 0x8b, 0xd0, 0xe0, 0xd8, 0xa5, - 0x54, 0xb9, 0xcb, 0x77, 0xe8, 0x0e, 0xd8, 0x66, - 0x0b, 0xc1, 0xcb, 0x17, 0xac, 0x7d, 0x84, 0x5b, - 0xe4, 0x0a, 0x7a, 0x02, 0x2d, 0x33, 0x06, 0xf1, - 0x16, 0xae, 0x9f, 0x81, 0xfe, 0xa6, 0x59, 0x47, - }, - }, - { - {0x7f, 0xff, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x07, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0xff, 0xfe, 0x08, 0x00, 0x00, 0x1f, - 0xf0, 0x00, 0x1f, 0xff, }, - {0x66, 0x70, 0xc2, 0x0a, 0xfc, 0xce, 0xae, 0xa6, - 0x72, 0xc9, 0x7f, 0x75, 0xe2, 0xe9, 0xdd, 0x5c, - 0x84, 0x60, 0xe5, 0x4b, 0xb3, 0x85, 0x38, 0xeb, - 0xb4, 0xbd, 0x30, 0xeb, 0xf2, 0x80, 0xd8, 0x00, - 0x8d, 0x07, 0xa4, 0xca, 0xf5, 0x42, 0x71, 0xf9, - 0x93, 0x52, 0x7d, 0x46, 0xff, 0x3f, 0xf4, 0x6f, - 0xd1, 0x19, 0x0a, 0x3f, 0x1f, 0xaa, 0x4f, 0x74, - }, - }, - { - {0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xc0, 0x00, 0x07, 0xff, 0xff, 0xe0, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x00, 0xff, - 0xff, 0xff, 0xff, 0xff, }, - {0x00, 0x0e, 0xca, 0x93, 0x42, 0x47, 0x42, 0x5c, - 0xfd, 0x94, 0x9b, 0x79, 0x5c, 0xb5, 0xce, 0x1e, - 0xff, 0x40, 0x15, 0x50, 0x38, 0x6e, 0x28, 0xd1, - 0xa4, 0xc5, 0xa8, 0xeb, 0xd4, 0xc0, 0x10, 0x40, - 0xdb, 0xa1, 0x96, 0x28, 0x93, 0x1b, 0xc8, 0x85, - 0x53, 0x70, 0x31, 0x7c, 0x72, 0x2c, 0xbd, 0x9c, - 0xa6, 0x15, 0x69, 0x85, 0xf1, 0xc2, 0xe9, 0xce, - }, - }, - { - {0x7f, 0xff, 0xfc, 0x03, 0xff, 0x80, 0x7f, 0xff, - 0xe0, 0x00, 0x1f, 0xff, 0xff, 0x80, 0x0f, 0xff, - 0x80, 0x00, 0x01, 0xff, 0xff, 0x00, 0x01, 0xff, - 0xff, 0xfe, 0x00, 0x1f, }, - {0xef, 0x35, 0x3b, 0xf5, 0xc7, 0x3c, 0xd5, 0x51, - 0xb9, 0x6d, 0x59, 0x6f, 0xbc, 0x9a, 0x67, 0xf1, - 0x6d, 0x61, 0xdd, 0x9f, 0xe5, 0x6a, 0xf1, 0x9d, - 0xe1, 0xfb, 0xa9, 0xcd, 0x21, 0x77, 0x1b, 0x9c, - 0xdc, 0xe3, 0xe8, 0x43, 0x0c, 0x09, 0xb3, 0x83, - 0x8b, 0xe7, 0x0b, 0x48, 0xc2, 0x1e, 0x15, 0xbc, - 0x09, 0xee, 0x1f, 0x2d, 0x79, 0x45, 0xb9, 0x1f, - }, - }, - { - {0x00, 0x00, 0x00, 0x07, 0xff, 0xc0, 0x7f, 0xff, - 0xff, 0xff, 0x01, 0xff, 0xfe, 0x03, 0xff, 0xfe, - 0x40, 0x00, 0x38, 0x00, 0x07, 0xe0, 0x00, 0x3f, - 0xfe, 0x00, 0x00, 0x00, }, - {0x40, 0x36, 0x05, 0x2a, 0x30, 0x91, 0xeb, 0x48, - 0x10, 0x46, 0xad, 0x32, 0x89, 0xc9, 0x5d, 0x3a, - 0xc9, 0x05, 0xca, 0x00, 0x23, 0xde, 0x2c, 0x03, - 0xec, 0xd4, 0x51, 0xcf, 0xd7, 0x68, 0x16, 0x5a, - 0x38, 0xa2, 0xb9, 0x6f, 0x81, 0x25, 0x86, 0xa9, - 0xd5, 0x9d, 0x41, 0x36, 0x03, 0x5d, 0x9c, 0x85, - 0x3a, 0x5b, 0xf2, 0xe1, 0xc8, 0x6a, 0x49, 0x93, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x29, }, - {0xfc, 0xc7, 0xf2, 0xb4, 0x5d, 0xf1, 0xcd, 0x5a, - 0x3c, 0x0c, 0x07, 0x31, 0xca, 0x47, 0xa8, 0xaf, - 0x75, 0xcf, 0xb0, 0x34, 0x7e, 0x83, 0x54, 0xee, - 0xfe, 0x78, 0x24, 0x55, 0xf2, 0xa2, 0x8e, 0xef, - 0xd8, 0xb3, 0x45, 0x83, 0x21, 0x16, 0xf1, 0xe5, - 0x74, 0xf2, 0xc6, 0xb2, 0xc8, 0x95, 0xaa, 0x8c, - 0x24, 0x94, 0x1f, 0x40, 0xd8, 0xb8, 0x0a, 0xd1, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x2a, }, - {0xa1, 0xe8, 0x1c, 0x04, 0xf3, 0x0c, 0xe2, 0x01, - 0xc7, 0xc9, 0xac, 0xe7, 0x85, 0xed, 0x44, 0xcc, - 0x33, 0xb4, 0x55, 0xa0, 0x22, 0xf2, 0xac, 0xdb, - 0xc6, 0xca, 0xe8, 0x3c, 0x23, 0x0e, 0x09, 0x3c, - 0x24, 0xf6, 0x38, 0xf5, 0x33, 0xda, 0xc6, 0xe2, - 0xb6, 0xd0, 0x1d, 0xa3, 0xb5, 0xe7, 0xf4, 0x54, - 0x29, 0x31, 0x5c, 0xa9, 0x3f, 0xb8, 0xe6, 0x34, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x2b, }, - {0xc9, 0xff, 0x61, 0xb0, 0x40, 0x87, 0x4c, 0x05, - 0x68, 0x47, 0x92, 0x16, 0x82, 0x4a, 0x15, 0xea, - 0xb1, 0xa8, 0x38, 0xa7, 0x97, 0xd1, 0x89, 0x74, - 0x62, 0x26, 0xe4, 0xcc, 0x15, 0x67, 0x29, 0xf1, - 0xa0, 0x03, 0x64, 0x70, 0x30, 0x66, 0x60, 0x54, - 0xe2, 0x08, 0x18, 0x0f, 0x8f, 0x7b, 0x0d, 0xf2, - 0x24, 0x9e, 0x44, 0xfb, 0xa5, 0x93, 0x1f, 0xff, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x2c, }, - {0xb8, 0x35, 0x7c, 0x3a, 0x6c, 0xee, 0xf2, 0x88, - 0x31, 0x0e, 0x17, 0xb8, 0xbf, 0xef, 0xf9, 0x20, - 0x08, 0x46, 0xca, 0x8c, 0x19, 0x42, 0x49, 0x7c, - 0x48, 0x44, 0x03, 0xbc, 0x00, 0xeb, 0x61, 0x05, - 0x99, 0xf9, 0x59, 0x42, 0xdf, 0x10, 0x82, 0xe4, - 0xf9, 0x42, 0x6d, 0x08, 0x6f, 0xb9, 0xc6, 0x23, - 0x1a, 0xe8, 0xb2, 0x49, 0x33, 0xaa, 0xb5, 0xdb, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x2d, }, - {0x0b, 0x6e, 0xc4, 0xfe, 0x17, 0x77, 0x38, 0x24, - 0x04, 0xef, 0x67, 0x99, 0x97, 0xba, 0x8d, 0x1c, - 0xc5, 0xcd, 0x8e, 0x85, 0x34, 0x92, 0x59, 0xf5, - 0x90, 0xc4, 0xc6, 0x6d, 0xcc, 0x66, 0x2b, 0x9b, - 0xcb, 0xa6, 0xf9, 0x4e, 0xe4, 0xff, 0x1c, 0x9c, - 0x10, 0xbd, 0x6d, 0xdd, 0x0d, 0x13, 0x8d, 0xf2, - 0xd0, 0x99, 0xa2, 0x82, 0x15, 0x2a, 0x4b, 0x7f, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x2e, }, - {0xba, 0xa4, 0xd8, 0x63, 0x55, 0x11, 0xa7, 0xd2, - 0x88, 0xae, 0xbe, 0xed, 0xd1, 0x2c, 0xe5, 0x29, - 0xff, 0x10, 0x2c, 0x91, 0xf9, 0x7f, 0x86, 0x7e, - 0x21, 0x91, 0x6b, 0xf9, 0x68, 0x65, 0xa0, 0xb8, - 0xa6, 0x07, 0xf0, 0xb0, 0x4b, 0x13, 0xd1, 0xcb, - 0x0a, 0xa9, 0x92, 0xa5, 0xa9, 0x7f, 0x5e, 0xe8, - 0xca, 0x18, 0x49, 0xef, 0xb9, 0xed, 0x86, 0x78, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x2f, }, - {0xa5, 0x36, 0x40, 0xc8, 0x3d, 0xc2, 0x08, 0x60, - 0x3d, 0xed, 0x83, 0xe4, 0xec, 0xf7, 0x58, 0xf2, - 0x4c, 0x35, 0x7d, 0x7c, 0xf4, 0x80, 0x88, 0xb2, - 0xce, 0x01, 0xe9, 0xfa, 0x2a, 0x7e, 0xb3, 0x28, - 0xdb, 0xe6, 0x63, 0xb5, 0xa4, 0x68, 0xb5, 0xbc, - 0x97, 0xa0, 0x40, 0xa3, 0x74, 0x53, 0x96, 0xba, - 0x63, 0x6b, 0x96, 0x43, 0x70, 0xdc, 0x33, 0x52, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x30, }, - {0x34, 0xe8, 0xe1, 0x7a, 0x43, 0x0e, 0x43, 0x28, - 0x97, 0x93, 0xc3, 0x83, 0xfa, 0xc9, 0x77, 0x42, - 0x47, 0xb4, 0x0e, 0x9e, 0xbd, 0x33, 0x66, 0x98, - 0x1f, 0xcf, 0xae, 0xca, 0xda, 0xd7, 0xe6, 0x08, - 0xe3, 0x80, 0x48, 0x04, 0x34, 0xea, 0x64, 0x1c, - 0xc8, 0x2c, 0x82, 0xcb, 0xc9, 0x28, 0x01, 0x46, - 0x9c, 0x8d, 0xb0, 0x20, 0x4f, 0x13, 0x48, 0x9a, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x31, }, - {0x6e, 0x31, 0xee, 0x1d, 0xc1, 0x37, 0xf8, 0x1b, - 0x05, 0x67, 0x52, 0xe4, 0xde, 0xab, 0x14, 0x43, - 0xa4, 0x81, 0x03, 0x3e, 0x9b, 0x4c, 0x93, 0xa3, - 0x04, 0x4f, 0x4f, 0x7a, 0xdf, 0x82, 0x22, 0x0f, - 0xc7, 0xa4, 0x02, 0x15, 0x49, 0x16, 0x53, 0x25, - 0x72, 0x5f, 0x94, 0xc3, 0x41, 0x0d, 0xdb, 0x56, - 0xc5, 0x4e, 0x16, 0x1f, 0xc9, 0xef, 0x62, 0xee, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x32, }, - {0xef, 0x53, 0xb6, 0x29, 0x4a, 0xca, 0x43, 0x1f, - 0x0f, 0x3c, 0x22, 0xdc, 0x82, 0xeb, 0x90, 0x50, - 0x32, 0x4f, 0x1d, 0x88, 0xd3, 0x77, 0xe7, 0x16, - 0x44, 0x8e, 0x50, 0x7c, 0xdf, 0x4a, 0xef, 0xff, - 0xbf, 0x6d, 0x16, 0x99, 0xc9, 0x30, 0x48, 0x1c, - 0xd1, 0x02, 0x12, 0x7c, 0x9a, 0x3d, 0x99, 0x20, - 0x48, 0xab, 0x05, 0x92, 0x9b, 0x6e, 0x59, 0x27, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x33, }, - {0xae, 0xa9, 0xe1, 0x7a, 0x30, 0x65, 0x17, 0xeb, - 0x89, 0x15, 0x2a, 0xa7, 0x09, 0x6d, 0x2c, 0x38, - 0x1e, 0xc8, 0x13, 0xc5, 0x1a, 0xa8, 0x80, 0xe7, - 0xbe, 0xe2, 0xc0, 0xfd, 0xc6, 0x44, 0xcf, 0x15, - 0x4c, 0xc8, 0x1f, 0x5a, 0xde, 0x49, 0x34, 0x5e, - 0x54, 0x1b, 0x4d, 0x4b, 0x5c, 0x1a, 0xdb, 0x3e, - 0xb5, 0xc0, 0x1c, 0x14, 0xee, 0x94, 0x9a, 0xa2, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x34, }, - {0x2f, 0xdc, 0xcc, 0xfe, 0xe7, 0x20, 0xa7, 0x7e, - 0xf6, 0xcb, 0x3b, 0xfb, 0xb4, 0x47, 0xf9, 0x38, - 0x31, 0x17, 0xe3, 0xda, 0xa4, 0xa0, 0x7e, 0x36, - 0xed, 0x15, 0xf7, 0x8d, 0xc8, 0xe8, 0xcd, 0x1b, - 0x0b, 0xe4, 0x0b, 0x08, 0x77, 0xcf, 0xca, 0x19, - 0x58, 0x60, 0x31, 0x22, 0xf1, 0xe6, 0x91, 0x4f, - 0x84, 0xb7, 0xe8, 0xe9, 0x68, 0xae, 0x8b, 0x9e, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x35, }, - {0x85, 0x8e, 0x6f, 0x9c, 0xc6, 0xc1, 0x2c, 0x31, - 0xf5, 0xdf, 0x12, 0x4a, 0xa7, 0x77, 0x67, 0xb0, - 0x5c, 0x8b, 0xc0, 0x21, 0xbd, 0x68, 0x3d, 0x2b, - 0x55, 0x57, 0x15, 0x50, 0xfb, 0x92, 0x32, 0xc1, - 0x5a, 0x3b, 0xc7, 0x67, 0x3a, 0x3a, 0x03, 0xb0, - 0x25, 0x38, 0x24, 0xc5, 0x3d, 0x0f, 0xd1, 0x41, - 0x1b, 0x1c, 0xab, 0xe2, 0xe1, 0x87, 0xfb, 0x87, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x36, }, - {0xdb, 0x2f, 0x6b, 0xe6, 0x30, 0xe2, 0x46, 0xa5, - 0xcf, 0x7d, 0x99, 0xb8, 0x51, 0x94, 0xb1, 0x23, - 0xd4, 0x87, 0xe2, 0xd4, 0x66, 0xb9, 0x4b, 0x24, - 0xa0, 0x3c, 0x3e, 0x28, 0xf0, 0xc5, 0xcf, 0xf7, - 0xab, 0x68, 0x0d, 0x09, 0xee, 0x11, 0xda, 0xe8, - 0x4e, 0x9c, 0x10, 0x72, 0xac, 0x48, 0xea, 0x2e, - 0x74, 0x4b, 0x1b, 0x7f, 0x72, 0xfd, 0x46, 0x9e, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x37, }, - {0x1f, 0x24, 0x83, 0xf8, 0x25, 0x72, 0x25, 0x1f, - 0xca, 0x97, 0x5f, 0xea, 0x40, 0xdb, 0x82, 0x1d, - 0xf8, 0xad, 0x82, 0xa3, 0xc0, 0x02, 0xee, 0x6c, - 0x57, 0x11, 0x24, 0x08, 0x76, 0x05, 0x0f, 0x33, - 0x48, 0xaf, 0x26, 0x64, 0xaa, 0xc3, 0xa8, 0xb0, - 0x52, 0x81, 0x30, 0x4e, 0xbc, 0x7a, 0x79, 0x14, - 0xc6, 0xad, 0x50, 0xa4, 0xb4, 0xea, 0xc3, 0x83, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x38, }, - {0x31, 0xc4, 0x9a, 0xe7, 0x5b, 0xce, 0x78, 0x07, - 0xcd, 0xff, 0x22, 0x05, 0x5d, 0x94, 0xee, 0x90, - 0x21, 0xfe, 0xdb, 0xb5, 0xab, 0x51, 0xc5, 0x75, - 0x26, 0xf0, 0x11, 0xaa, 0xd8, 0x17, 0x40, 0x0e, - 0x8b, 0xa9, 0xca, 0x13, 0xa4, 0x5f, 0x36, 0x0e, - 0x3d, 0x12, 0x1e, 0xaa, 0xeb, 0x39, 0xaf, 0x82, - 0xd6, 0x00, 0x1c, 0x81, 0x86, 0xf5, 0xf8, 0x66, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x39, }, - {0xae, 0x99, 0xfe, 0xeb, 0xb5, 0xd2, 0x69, 0x45, - 0xb5, 0x48, 0x92, 0x09, 0x2a, 0x8a, 0xee, 0x02, - 0x91, 0x29, 0x30, 0xfa, 0x41, 0xcd, 0x11, 0x4e, - 0x40, 0x44, 0x73, 0x01, 0xfb, 0x7d, 0xa7, 0xf5, - 0xf1, 0x3a, 0x43, 0xb8, 0x17, 0x74, 0x37, 0x3c, - 0x87, 0x9c, 0xd3, 0x2d, 0x69, 0x34, 0xc0, 0x5f, - 0xa7, 0x58, 0xee, 0xb1, 0x4f, 0xcf, 0xab, 0x38, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x3a, }, - {0xdf, 0x1b, 0x1d, 0x66, 0xa5, 0x51, 0xd0, 0xd3, - 0x1e, 0xff, 0x82, 0x25, 0x58, 0xb9, 0xd2, 0xcc, - 0x75, 0xc2, 0x18, 0x02, 0x79, 0xfe, 0x0d, 0x08, - 0xfd, 0x89, 0x6d, 0x04, 0x5c, 0x08, 0x0f, 0xc3, - 0x52, 0x2f, 0x41, 0xbb, 0xb3, 0xf5, 0x5a, 0x97, - 0xcf, 0xec, 0xf2, 0x1f, 0x88, 0x2c, 0xe8, 0xcb, - 0xb1, 0xe5, 0x0c, 0xa6, 0xe6, 0x7e, 0x56, 0xdc, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x3b, }, - {0x70, 0x6a, 0x46, 0xdc, 0x76, 0xdc, 0xb7, 0x67, - 0x98, 0xe6, 0x0e, 0x6d, 0x89, 0x47, 0x47, 0x88, - 0xd1, 0x6d, 0xc1, 0x80, 0x32, 0xd2, 0x68, 0xfd, - 0x1a, 0x70, 0x4f, 0xa6, 0xe3, 0xd4, 0x89, 0x58, - 0x43, 0xda, 0x18, 0x8f, 0xd5, 0x8f, 0xb0, 0x56, - 0x79, 0x76, 0xd7, 0xb5, 0x03, 0x59, 0xd6, 0xb7, - 0x85, 0x30, 0xc8, 0xf6, 0x2d, 0x1b, 0x17, 0x46, - }, - }, - { - {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x16, 0xa2, - 0xe0, 0xb8, 0xf0, 0x3e, 0x13, 0xdd, 0x29, 0x45, - 0x5c, 0x5c, 0x2a, 0x3c, }, - {0xb7, 0x0e, 0x0c, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, - 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x03, 0xc1, 0xd3, - 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, - 0x11, 0x5c, 0x1d, 0x21, 0x42, 0xc8, 0x9c, 0x77, - 0x4a, 0x08, 0xdc, 0x04, 0xb3, 0xdd, 0x20, 0x19, - 0x32, 0xbc, 0x8a, 0x5e, 0xa5, 0xf8, 0xb8, 0x9b, - 0xbb, 0x2a, 0x7e, 0x66, 0x7a, 0xff, 0x81, 0xcd, - }, - }, -}; - -void testScalarBaseMult() { - p224_point point; - int i; - - for (i = 0; i < kNumNISTTestVectors; i++) { - uint8_t bin[56]; - p224_base_point_mul(kNISTTestVectors[i].scalar, &point); - p224_point_to_bin(&point, bin); - if (memcmp(bin, kNISTTestVectors[i].affine, 56) != 0) { - printf("testScalarBaseMult fail!\n"); - exit(1); - } - } -} - -void testScalarMult() { - p224_point point; - p224_point basepoint; - int i; - - p224_point_from_bin(kBasePointExternal, sizeof(kBasePointExternal), &basepoint); - - for (i = 0; i < kNumNISTTestVectors; i++) { - uint8_t bin[56]; - p224_point_mul(&basepoint, kNISTTestVectors[i].scalar, &point); - p224_point_to_bin(&point, bin); - if (memcmp(bin, kNISTTestVectors[i].affine, 56) != 0) { - printf("testScalarMult fail!\n"); - exit(1); - } - } -} - -int main(int argc, char* argv[]) { - testScalarBaseMult(); - testScalarMult(); - return 0; -} diff --git a/omaha/base/security/p256.c b/omaha/base/security/p256.c index fef587e89..b578cf968 100644 --- a/omaha/base/security/p256.c +++ b/omaha/base/security/p256.c @@ -395,6 +395,8 @@ int p256_is_valid_point(const p256_int* x, const p256_int* y) { if (p256_sub(&x3, x, &x3)) p256_add(&x3, &SECP256r1_p, &x3); // x^3 - 3x if (p256_add(&x3, &SECP256r1_b, &x3)) // x^3 - 3x + b p256_sub(&x3, &SECP256r1_p, &x3); + if (p256_sub(&x3, &SECP256r1_p, &x3)) // make sure 0 <= x3 < p + p256_add(&x3, &SECP256r1_p, &x3); return p256_cmp(&y2, &x3) == 0; } diff --git a/omaha/base/security/p256_ecdsa.c b/omaha/base/security/p256_ecdsa.c index 338760bab..d6578b2be 100644 --- a/omaha/base/security/p256_ecdsa.c +++ b/omaha/base/security/p256_ecdsa.c @@ -26,7 +26,7 @@ static void determine_k(const p256_int* key, do { p256_int p1, p2; - HMAC_CTX hmac; + LITE_HMAC_CTX hmac; // Note: taking the p256_int in-memory representation is not // endian neutral. Signatures with an identical key on identical diff --git a/omaha/base/security/p256_prng.c b/omaha/base/security/p256_prng.c index b9bb260cd..581226dde 100644 --- a/omaha/base/security/p256_prng.c +++ b/omaha/base/security/p256_prng.c @@ -32,7 +32,7 @@ static void uint64tobin(uint64_t v, uint8_t* t) { // V = HMAC(K, V) static void update_V(P256_PRNG_CTX* ctx) { - HMAC_CTX hmac; + LITE_HMAC_CTX hmac; HMAC_SHA256_init(&hmac, ctx->Key, P256_PRNG_SIZE); HMAC_update(&hmac, ctx->V, P256_PRNG_SIZE); memcpy(ctx->V, HMAC_final(&hmac), P256_PRNG_SIZE); @@ -41,7 +41,7 @@ static void update_V(P256_PRNG_CTX* ctx) { // K = HMAC(K, V || [0,1] || count || seed) static void update_Key(P256_PRNG_CTX* ctx, int which, const void* seed, size_t seed_size) { - HMAC_CTX hmac; + LITE_HMAC_CTX hmac; uint8_t tmp[16 + 1]; HMAC_SHA256_init(&hmac, ctx->Key, P256_PRNG_SIZE); diff --git a/omaha/base/security/p256_unittest.c b/omaha/base/security/p256_unittest.c new file mode 100644 index 000000000..5e5de9798 --- /dev/null +++ b/omaha/base/security/p256_unittest.c @@ -0,0 +1,136 @@ +#include +#include +#include + +#include "p256.h" + +#define _TOSTR(x) #x +#define TOSTR(x) _TOSTR(x) +#define CHECK(x) \ + do { if (!(x)) { \ + errno = EADV; \ + perror(#x " @ line " TOSTR(__LINE__)); exit(1); }} while(0) + +static int count_bits(const p256_int* a) { + int i, n = 0; + for (i = 0; i < 256; ++i) { + n += p256_get_bit(a, i); + } + return n; +} + +// Confirm the CPU's right shift is an arithmetic shift +void test_cpu_behavior() { + int32_t i; + volatile int32_t val = -1; + uint32_t one = 1; + + for (i = 0; i < 32; i++) { + CHECK((val>>i) == (-1)); + } + + for (i = 0; i < 32; i++) { + CHECK(0 != (((uint32_t)(val>>i)) & (one< 0; --i) { + CHECK(p256_get_bit(&a, i) == 1); + CHECK(!p256_is_zero(&a)); + p256_shr(&a, 1, &a); + CHECK(p256_get_bit(&a, i) == 0); + CHECK(count_bits(&a) == 1); + } + + CHECK(p256_get_bit(&a, i) == 1); + CHECK(!p256_is_zero(&a)); + + // Shift bit out bottom. + p256_shr(&a, 1, &a); + CHECK(p256_is_zero(&a)); +} + +void test_add_sub_cmp() { + p256_int a = {{1}}; + p256_int b; + p256_int one = {{1}}; + int i; + + for (i = 0; i < 255; ++i) { + CHECK(count_bits(&a) == 1); + CHECK(p256_sub(&a, &one, &b) == 0); + CHECK(p256_cmp(&a, &b) == 1); + CHECK(p256_cmp(&b, &a) == -1); + CHECK(count_bits(&b) == i); + CHECK(p256_add(&b, &one, &b) == 0); + CHECK(count_bits(&b) == 1); + CHECK(p256_cmp(&b, &a) == 0); + + CHECK(p256_shl(&a, 1, &a) == 0); + } + + CHECK(p256_add(&a, &a, &b) == 1); // expect carry + CHECK(p256_is_zero(&b)); + CHECK(p256_cmp(&b, &a) == -1); + CHECK(p256_sub(&b, &one, &b) == -1); // expect borrow + CHECK(p256_cmp(&b, &a) == 1); +} + +void test_mul_inv() { + p256_int a = {{1}}; + p256_int one = {{1}}; + p256_int b, c; + int i; + + for (i = 0; i < 255; ++i) { + p256_modinv(&SECP256r1_n, &a, &b); // b = 1/a + p256_modmul(&SECP256r1_n, &a, 0, &b, &c); // c = b * a = 1/a * a = 1 + CHECK(p256_cmp(&c, &one) == 0); + + p256_modinv_vartime(&SECP256r1_n, &b, &c); // c = 1/b = 1/1/a = a + CHECK(p256_cmp(&a, &c) == 0); + + CHECK(p256_shl(&a, 1, &a) == 0); + } +} + +void test_valid_point() { + // Constructed x where p < x^3-3x+b < 2^256, unreduced. + // Computed matching y to make valid point. + p256_int x = {{0x3de86868, 0x1c4c6c08, 0x22d79c, 0, 0, 0, 0, 0}}; + p256_int y = {{0xf7cc27ae, 0x29181e9d, 0xcb78ccd6, 0x43800616, + 0x86508edc, 0x13f5f534, 0x138ffcd1, 0x6b1c4fae}}; + + CHECK(p256_is_valid_point(&x, &y) == 1); +} + +int main(int argc, char* argv[]) { + test_cpu_behavior(); + test_shifts(); + test_add_sub_cmp(); + test_mul_inv(); + test_valid_point(); + return 0; +} diff --git a/omaha/base/security/pbkdf2.c b/omaha/base/security/pbkdf2.c deleted file mode 100644 index 3a288e375..000000000 --- a/omaha/base/security/pbkdf2.c +++ /dev/null @@ -1,81 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#include - -#include "pbkdf2.h" -#include "sha256.h" -#include "hmac.h" - -// Implemented as per RFC 2898 - -static void F(const HMAC_CTX* initialized_ctx, - const uint8_t* salt, uint32_t salt_len, - uint32_t iterations, uint32_t i, - uint8_t digest_acc[SHA256_DIGEST_SIZE] // output - ) { - HMAC_CTX ctx; - uint8_t digest_tmp[SHA256_DIGEST_SIZE]; - uint8_t i_buf[4]; - uint32_t iter; - uint32_t j; - - i_buf[0] = (uint8_t)((i >> 24) & 0xff); - i_buf[1] = (uint8_t)((i >> 16) & 0xff); - i_buf[2] = (uint8_t)((i >> 8) & 0xff); - i_buf[3] = (uint8_t)(i & 0xff); - ctx = *initialized_ctx; - // First iteration uses password as key, salt || big_endian(i) as input - HMAC_update (&ctx, salt, salt_len); - HMAC_update (&ctx, i_buf, 4); - memcpy (digest_tmp, HMAC_final(&ctx), SHA256_DIGEST_SIZE); - memcpy (digest_acc, digest_tmp, SHA256_DIGEST_SIZE); - // Next count - 1 iterations use previous digest value. - // All successive digest values XORed together into digest_acc[umulator] - for (iter = 1; iter < iterations; iter++) { - ctx = *initialized_ctx; - HMAC_update (&ctx, digest_tmp, SHA256_DIGEST_SIZE); - memcpy (digest_tmp, HMAC_final(&ctx), SHA256_DIGEST_SIZE); - for (j = 0; j < SHA256_DIGEST_SIZE; j++) { - digest_acc[j] ^= digest_tmp[j]; - } - } -} - -void pbkdf2_hmac_sha256(const uint8_t* password, uint32_t password_len, - const uint8_t* salt, uint32_t salt_len, - uint32_t count, uint32_t dkLen, uint8_t* dk) { - uint32_t i, l, r; - uint8_t digest_tmp[SHA256_DIGEST_SIZE]; // used for final [partial] block - HMAC_CTX ctx; - - if (dkLen < 1) { // If they ask for 0 bytes, there is no work to do - return; - } - - // l = ceiling (dkLen / SHA256_DIGEST_SIZE) - l = (dkLen + SHA256_DIGEST_SIZE - 1) / SHA256_DIGEST_SIZE; - r = dkLen - (l - 1) * SHA256_DIGEST_SIZE; - - HMAC_SHA256_init (&ctx, password, password_len); - - // First l-1 blocks, indexed from 1 - for (i = 1; i < l; i++) { - F (&ctx, salt, salt_len, count, i, &dk[(i-1)*SHA256_DIGEST_SIZE]); - } - // Final (possibly partial) block of r bytes - F (&ctx, salt, salt_len, count, i, digest_tmp); - memcpy (&dk[(l - 1)*SHA256_DIGEST_SIZE], digest_tmp, r); -} diff --git a/omaha/base/security/pbkdf2.h b/omaha/base/security/pbkdf2.h deleted file mode 100644 index 11ebbf2fe..000000000 --- a/omaha/base/security/pbkdf2.h +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#ifndef OMAHA_BASE_SECURITY_PBKDF2_H_ -#define OMAHA_BASE_SECURITY_PBKDF2_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -// Implements PBKDF2-HMAC-SHA256 per RFC 2898. dk is assumed to point to at -// least dkLen bytes of space. -void pbkdf2_hmac_sha256(const uint8_t* password, uint32_t password_len, - const uint8_t* salt, uint32_t salt_len, - uint32_t count, uint32_t dkLen, uint8_t* dk); - -#ifdef __cplusplus -} // extern "C" -#endif - -#endif // OMAHA_BASE_SECURITY_PBKDF2_H_ - diff --git a/omaha/base/security/pbkdf2_test.cc b/omaha/base/security/pbkdf2_test.cc deleted file mode 100644 index 826a425b3..000000000 --- a/omaha/base/security/pbkdf2_test.cc +++ /dev/null @@ -1,112 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#include "security/util/lite/pbkdf2.h" -#include "strings/escaping.h" -#include "testing/base/public/gunit.h" - -namespace { - -class Pbkdf2Test : public ::testing::Test { - protected: -}; - -struct TestVector { - const char* password; - const uint32_t password_len; - const char* salt; - const uint32_t salt_len; - const uint32_t count; - const uint32_t dkLen; - const char* expected_dk; -}; - -static const struct TestVector vectors[] = { - { "password", 8, "salt", 4, 1, 32, - "120fb6cffcf8b32c43e7225256c4f837a86548c92ccc35480805987cb70be17b" }, - { "password", 8, "salt", 4, 2, 32, - "ae4d0c95af6b46d32d0adff928f06dd02a303f8ef3c251dfd6e2d85a95474c43" }, - { "password", 8, "salt", 4, 4096, 32, - "c5e478d59288c841aa530db6845c4c8d962893a001ce4e11a4963873aa98134a" }, - { "passwordPASSWORDpassword", 24, "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, - 4096, 40, - "348c89dbcbd32b2f32d814b8116e84cf2b17347e" - "bc1800181c4e2a1fb8dd53e1c635518c7dac47e9" }, - { "pass\0word", 9, "sa\0lt", 5, 4096, 16, "89b69d0516f829893c696226650a8687"}, - { "password", 8, "salt", 4, 1, 20, - "120fb6cffcf8b32c43e7225256c4f837a86548c9" }, - { "password", 8, "salt", 4, 2, 20, - "ae4d0c95af6b46d32d0adff928f06dd02a303f8e" }, - { "password", 8, "salt", 4, 4096, 20, - "c5e478d59288c841aa530db6845c4c8d962893a0" }, - { "passwordPASSWORDpassword", 24, "saltSALTsaltSALTsaltSALTsaltSALTsalt", 36, - 4096, 25, - "348c89dbcbd32b2f32d814b8116e84cf2b17347ebc1800181c" }, - { "pass\0word", 9, "sa\0lt", 5, 4096, 16, - "89b69d0516f829893c696226650a8687" }, -}; - -TEST_F(Pbkdf2Test, KnownTestVectors) { - uint8_t derived_key[1024]; - - for (uint32_t i = 0; i < sizeof(vectors)/sizeof(*vectors); i++) { - const struct TestVector* v = &vectors[i]; - - pbkdf2_hmac_sha256((const uint8_t*)v->password, v->password_len, - (const uint8_t*)v->salt, v->salt_len, - v->count, - v->dkLen, derived_key); - - LOG(INFO) << "derived_key for vector " << i << ": " - << strings::b2a_hex(string( - reinterpret_cast(derived_key), v->dkLen)); - - EXPECT_EQ(string(v->expected_dk), - strings::b2a_hex(string( - reinterpret_cast(derived_key), v->dkLen))); - } -} - -static const struct TestVector slow_vectors[] = { - { "password", 8, "salt", 4, 16777216, 32, - "cf81c66fe8cfc04d1f31ecb65dab4089f7f179e89b3b0bcb17ad10e3ac6eba46" }, - { "password", 8, "salt", 4, 16777216, 20, - "cf81c66fe8cfc04d1f31ecb65dab4089f7f179e8" }, -}; - -// These test vectors take a few minutes each and thus it may not be desired -// to run them every time. -TEST_F(Pbkdf2Test, KnownSlowTestVectors) { - uint8_t derived_key[1024]; - - for (uint32_t i = 0; i < sizeof(slow_vectors)/sizeof(*slow_vectors); i++) { - const struct TestVector* v = &slow_vectors[i]; - - pbkdf2_hmac_sha256((const uint8_t*)v->password, v->password_len, - (const uint8_t*)v->salt, v->salt_len, - v->count, - v->dkLen, derived_key); - - LOG(INFO) << "derived_key for slow_vector " << i << ": " - << strings::b2a_hex(string( - reinterpret_cast(derived_key), v->dkLen)); - - EXPECT_EQ(string(v->expected_dk), - strings::b2a_hex(string( - reinterpret_cast(derived_key), v->dkLen))); - } -} - -} // namespace diff --git a/omaha/base/security/publickey.h b/omaha/base/security/publickey.h deleted file mode 100644 index 05d0e87fd..000000000 --- a/omaha/base/security/publickey.h +++ /dev/null @@ -1 +0,0 @@ -{4,32,0x04480a55,0x1ae203f1,0x23e95912,0x3630a36f,0x7c800660,0xb9433b1f,0x394322e7,0x297d3f11,0xcca3e481,0x40dd4037,0xf7bf42d8,0x5fed9e7c,0xe2b2b824,0x3d03e10c,0xaeb8b3c9,0x6ee6473f,0x4fe45331,0x5b7f3184,0x2c54183e,0x99037f01,0xd864b9d2,0x681472ab,0x01cf82fb,0x95e6b62c,0x98c1c41b,0x6ed0463e,0x0e7cc820,0x4993bc27,0xb8fdc1b6,0x004b2e9b,0xb58730a0,0xb2af3930,0xbbc15687,0x3ca95bb7,0x16a4a351,0x5ca051af,0x36ca7470,0x65ef3443,0x4b2a0e96,0x272cd317,0x2eff92d3,0xdb34bfbe,0x1fade9da,0xe01638d3,0x14e14dd9,0xf16c562e,0xb5df74fd,0xb07ca6fd,0x31728cf1,0xb5014e59,0x82196247,0x067005dd,0x6477efc7,0xd8dd44e8,0x8c3ad156,0x52338009,0x759cda44,0x7be9d442,0xf0eebec4,0x13ffd17b,0x8669ef5a,0x4ab27426,0xe58037f2,0x705b8d2c,0x3d7f4620} diff --git a/omaha/base/security/rc4.c b/omaha/base/security/rc4.c deleted file mode 100644 index 03969c9fe..000000000 --- a/omaha/base/security/rc4.c +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#include "rc4.h" - -#include - -void RC4_setKey(RC4_CTX* ctx, const uint8_t* key, int len) { - uint8_t* S = ctx->S; - int i, j; - - for (i = 0; i < 256; ++i) { - S[i] = i; - } - - j = 0; - for (i = 0; i < 256; ++i) { - uint8_t tmp; - - j = (j + S[i] + key[i % len]) & 255; - - tmp = S[i]; - S[i] = S[j]; - S[j] = tmp; - } - - ctx->i = 0; - ctx->j = 0; -} - -void RC4_crypt(RC4_CTX* ctx, - const uint8_t *in, - uint8_t* out, - int len) { - uint8_t i = ctx->i; - uint8_t j = ctx->j; - uint8_t* S = ctx->S; - - int n; - - for (n = 0; n < len; ++n) { - uint8_t tmp; - - i = (i + 1) & 255; - j = (j + S[i]) & 255; - - tmp = S[i]; - S[i] = S[j]; - S[j] = tmp; - - if (in) { - if (out) { - out[n] = in[n] ^ S[(S[i] + S[j]) & 255]; - } - } else { - if (out) { - out[n] = S[(S[i] + S[j]) & 255]; - } - } - } - - ctx->i = i; - ctx->j = j; -} - -void RC4_discard(RC4_CTX* ctx, int len) { - RC4_crypt(ctx, 0, 0, len); -} - -void RC4_stream(RC4_CTX* ctx, uint8_t* out, int len) { - RC4_crypt(ctx, 0, out, len); -} diff --git a/omaha/base/security/rc4.h b/omaha/base/security/rc4.h deleted file mode 100644 index 888f42f7a..000000000 --- a/omaha/base/security/rc4.h +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#ifndef OMAHA_BASE_SECURITY_RC4_H_ -#define OMAHA_BASE_SECURITY_RC4_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct { - uint8_t S[256]; - uint8_t i; - uint8_t j; -} RC4_CTX; - -void RC4_setKey(RC4_CTX* ctx, const uint8_t* data, int len); -void RC4_discard(RC4_CTX* ctx, int len); -void RC4_crypt(RC4_CTX* ctx, const uint8_t* in, uint8_t* out, int len); -void RC4_stream(RC4_CTX* ctx, uint8_t* out, int len); - -#ifdef __cplusplus -} -#endif - -#endif // OMAHA_BASE_SECURITY_RC4_H_ diff --git a/omaha/base/security/rsa.cc b/omaha/base/security/rsa.cc deleted file mode 100644 index 039989885..000000000 --- a/omaha/base/security/rsa.cc +++ /dev/null @@ -1,290 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#include "rsa.h" - -#include -#include -#include -#include - -#include "md5.h" -#include "aes.h" -#include "sha.h" -#include "rc4.h" - -#define DINV mod[0] -#define RR(i) mod[1 + 2*(i)] -#define MOD(i) (mod[2 + 2*(i)] + mod[1 + 2*(i)]) // +mod[1+2*(i)] to deobscure - -// -// a[] -= M -// -static void subM(uint32_t* a, const uint32_t* mod, int len) { - int64_t A = 0; - for (int i = 0; i < len; ++i) { - A += (uint64_t)a[i] - MOD(i); - a[i] = (uint32_t)A; - A >>= 32; - } -} - -// -// return a[] >= M -// -static bool geM(const uint32_t* a, const uint32_t* mod, int len) { - for (int i = len; i;) { - --i; - if (a[i] < MOD(i)) return false; - if (a[i] > MOD(i)) return true; - } - return true; // equal -} - -// -// montgomery c[] += a * b[] / R mod M -// -static void montMulAdd(uint32_t* c, - uint32_t a, - const uint32_t* b, - const uint32_t* mod, - int len) { - uint64_t A = (uint64_t)a * b[0] + c[0]; - uint32_t d0 = (uint32_t)A * DINV; - uint64_t B = (uint64_t)d0 * MOD(0) + (uint32_t)A; - - int i = 1; - for (; i < len; ++i) { - A = (A >> 32) + (uint64_t)a * b[i] + c[i]; - B = (B >> 32) + (uint64_t)d0 * MOD(i) + (uint32_t)A; - c[i - 1] = (uint32_t)B; - } - - A = (A >> 32) + (B >> 32); - - c[i - 1] = (uint32_t)A; - - if ((A >> 32)) { // proper probablistic padding could avoid this? - subM(c, mod, len); // or moduli without the highest bit set.. - } -} - -// -// montgomery c[] = a[] * R^2 / R mod M (= a[] * R mod M) -// -static void montMulR(uint32_t* c, - const uint32_t* a, - const uint32_t* mod, - int len) { - memset(c, 0, len * sizeof(uint32_t)); - - for (int i = 0; i < len; ++i) { - montMulAdd(c, RR(i), a, mod, len); - } -} - -// -// montgomery c[] = a[] * b[] / R mod M -// -static void montMul(uint32_t* c, - const uint32_t* a, - const uint32_t* b, - const uint32_t* mod, - int len) { - memset(c, 0, len * sizeof(uint32_t)); - - for (int i = 0; i < len; ++i) { - montMulAdd(c, a[i], b, mod, len); - } -} - - -// -// In-place public exponentiation. -// Input and output big-endian byte array. -// Returns 0 on failure or # uint8_t written in inout (always inout_len). -// -int RSA::raw(uint8_t* inout, int inout_len) const { - const uint32_t* mod = &pkey_[1]; - int len = *mod++; - - if (len > kMaxWords) - return 0; // Only work with up to 2048 bit moduli. - if ((len * 4) != inout_len) - return 0; // Input length should match modulus length. - - uint32_t a[kMaxWords]; - - // Convert from big endian byte array to little endian word array. - for (int i = 0; i < len; ++i) { - uint32_t tmp = - (inout[((len - 1 - i) * 4) + 0] << 24) | - (inout[((len - 1 - i) * 4) + 1] << 16) | - (inout[((len - 1 - i) * 4) + 2] << 8) | - (inout[((len - 1 - i) * 4) + 3] << 0); - a[i] = tmp; - } - - uint32_t aR[kMaxWords]; - uint32_t aaR[kMaxWords]; - uint32_t aaa[kMaxWords]; - - montMulR(aR, a, mod, len); // aR = a * R mod M - montMul(aaR, aR, aR, mod, len); // aaR = a^2 * R mod M - montMul(aaa, aaR, a, mod, len); // aaa = a^3 mod M - - // Make sure aaa < mod; aaa is at most 1x mod too large. - if (geM(aaa, mod, len)) { - subM(aaa, mod, len); - } - - // Convert to bigendian byte array - int reslen = 0; - - for (int i = len - 1; i >= 0; --i) { - uint32_t tmp = aaa[i]; - inout[reslen++] = tmp >> 24; - inout[reslen++] = tmp >> 16; - inout[reslen++] = tmp >> 8; - inout[reslen++] = tmp >> 0; - } - - return reslen; -} - -// -// Verify a Google style padded message recovery signature and return the -// message. -// -int RSA::verify(const uint8_t* data, int data_len, - void* output, int output_len) const { - uint8_t res[kMaxWords * 4]; - - if (data_len < 0 || data_len > (kMaxWords * 4)) - return 0; // Input too big, 2048 bit max. - - memcpy(res, data, data_len); - - int reslen = this->raw(res, data_len); - - if (!reslen) return 0; - - uint8_t md5[16]; - - MD5_hash(res, reslen - 16, md5); - - for (int i = 0; i < 16; ++i) { - res[reslen - 16 + i] ^= md5[i]; - } - - // Unmask low part using high part as ofb key. - uint8_t iv[16] = {0}; - - for (int i = 0; i < reslen - 16; i++) { - if (!(i & 15)) - AES_encrypt_block(res + reslen - 16, iv, iv); - res[i] ^= iv[i & 15]; - } - - res[0] &= 127; - res[0] %= reslen - 16 - 16; - - bool result = true; - - // Verify high part is hash of random in low part. - MD5_hash(res + 1, res[0] + 16, md5); - for (int i = 0; i < 16; ++i) { - result = result && (res[reslen - 16 + i] == md5[i]); - } - - if (!result) { - return 0; // verification failure - } - - // Copy message into output[] - if (res[0] > output_len) { - return 0; // output too small, return failure - } - - memcpy(output, res + 1, res[0]); - - return res[0]; -} - -// -// Hybrid encrypt message. -// Make up RC4 key using seed and hash of msg. -// Wrap key with RSA, encrypt msg with RC4. -// -int RSA::encrypt(const uint8_t* msg, int msg_len, - const void* seed, int seed_len, - uint8_t* output, int output_max) const { - int output_len = this->encryptedSize(msg_len); - if (output_max < 0 || output_max < output_len) - return 0; - - int header_size = output_len - msg_len; // Our added overhead. - - // Hash of message. Least significant SHA_DIGEST_SIZE bytes of RSA number. - uint8_t* hash = &output[header_size - SHA_DIGEST_SIZE]; - SHA_hash(msg, msg_len, hash); - - // Hash(Hash(message) | seed). - SHA_CTX sha; - SHA_init(&sha); - SHA_update(&sha, hash, SHA_DIGEST_SIZE); - SHA_update(&sha, seed, seed_len); - - // Use this Hash(Hash(message) | seed) as RC4 key for prng. - RC4_CTX rc4; - RC4_setKey(&rc4, SHA_final(&sha), SHA_DIGEST_SIZE); - RC4_discard(&rc4, 1536); // Drop some to warm up RC4. - - uint8_t* key = &output[1 + 4]; - - // Prng conjure some bytes. - RC4_stream(&rc4, key, this->size() - SHA_DIGEST_SIZE); - key[0] &= 127; // Drop top bit to be less than modulus. - - // Mask plaintext hash with hash of prng part. - SHA_init(&sha); - SHA_update(&sha, key, this->size() - SHA_DIGEST_SIZE); - const uint8_t* mask = SHA_final(&sha); - for (int i = 0; i < SHA_DIGEST_SIZE; ++i) - hash[i] ^= mask[i]; - - // Use entire RSA number as content encryption key. - RC4_setKey(&rc4, key, this->size()); - RC4_discard(&rc4, 1536); // Warm up RC4. - - // Output wire-format version, single 0 byte. - output[0] = 0; - - // Output version, msb first. - uint32_t version = this->version(); - output[1] = version >> 24; - output[2] = version >> 16; - output[3] = version >> 8; - output[4] = version >> 0; - - // Wrap key data with public RSA key. - if (!this->raw(key, this->size())) - return 0; - - // Append encrypted message. - RC4_crypt(&rc4, msg, &output[header_size], msg_len); - - return output_len; -} diff --git a/omaha/base/security/rsa.h b/omaha/base/security/rsa.h deleted file mode 100644 index ac06fc46e..000000000 --- a/omaha/base/security/rsa.h +++ /dev/null @@ -1,67 +0,0 @@ -// Copyright 2007-2009 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#ifndef OMAHA_BASE_SECURITY_RSA_H_ -#define OMAHA_BASE_SECURITY_RSA_H_ - -#include - -class RSA { - public: - typedef const uint32_t PublicKeyInstance[]; - typedef const uint32_t* PublicKey; - - // Public_key as montgomery precomputed array, as per - // /home/build/static/projects/security/util/lite/keytool --pubout - explicit RSA(PublicKey public_key) : pkey_(public_key) {} - - // Verifies a Google style RSA message recovery signature. - // - // sig[] signature to verify, big-endian byte array. - // sig_len length of sig[] in bytes. - // If verified successfully, output receives the recovered - // message and the function returns the number of bytes. - // If not successful, the function returns 0. - // (empty message is not a useful message) - int verify(const uint8_t* sig, int sig_len, - void* output, int output_max) const; - - // Hybrid encrypt message. See wiki/Main/KeymasterCryptoFormats. - // - // output_max should be at least encryptedSize(msg_len) - // Returns 0 on failure, # output bytes on success. - int encrypt(const uint8_t* msg, int msg_len, - const void* seed, int seed_len, - uint8_t* output, int output_max) const; - - int encryptedSize(int len) const { - return len + 1 + 4 + size(); - } - - // Performs in-place public key exponentiation. - // - // Input_len should match size of modulus in bytes. - // Returns 0 on failure, # of bytes written on success. - int raw(uint8_t* input, int input_len) const; - - int version() const { return pkey_[0]; } - int size() const { return pkey_[1] * 4; } - - private: - const PublicKey pkey_; - static const int kMaxWords = 64; -}; - -#endif // OMAHA_BASE_SECURITY_RSA_H_ diff --git a/omaha/base/security/sha256.c b/omaha/base/security/sha256.c index 380db7941..65c26c912 100644 --- a/omaha/base/security/sha256.c +++ b/omaha/base/security/sha256.c @@ -41,7 +41,7 @@ static const uint32_t K[64] = { 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 }; -static void SHA256_Transform(SHA256_CTX* ctx) { +static void SHA256_Transform(LITE_SHA256_CTX* ctx) { uint32_t W[64]; uint32_t A, B, C, D, E, F, G, H; uint8_t* p = ctx->buf; @@ -106,7 +106,7 @@ static const HASH_VTAB SHA256_VTAB = { SHA256_DIGEST_SIZE }; -void SHA256_init(SHA256_CTX* ctx) { +void SHA256_init(LITE_SHA256_CTX* ctx) { ctx->f = &SHA256_VTAB; ctx->state[0] = 0x6a09e667; ctx->state[1] = 0xbb67ae85; @@ -120,7 +120,7 @@ void SHA256_init(SHA256_CTX* ctx) { } -void SHA256_update(SHA256_CTX* ctx, const void* data, unsigned int len) { +void SHA256_update(LITE_SHA256_CTX* ctx, const void* data, unsigned int len) { int i = (int) (ctx->count & 63); const uint8_t* p = (const uint8_t*)data; @@ -136,7 +136,7 @@ void SHA256_update(SHA256_CTX* ctx, const void* data, unsigned int len) { } -const uint8_t* SHA256_final(SHA256_CTX* ctx) { +const uint8_t* SHA256_final(LITE_SHA256_CTX* ctx) { uint8_t *p = ctx->buf; uint64_t cnt = ctx->count * 8; int i; @@ -164,7 +164,7 @@ const uint8_t* SHA256_final(SHA256_CTX* ctx) { /* Convenience function */ const uint8_t* SHA256_hash(const void* data, unsigned int len, uint8_t* digest) { - SHA256_CTX ctx; + LITE_SHA256_CTX ctx; SHA256_init(&ctx); SHA256_update(&ctx, data, len); memcpy(digest, SHA256_final(&ctx), SHA256_DIGEST_SIZE); diff --git a/omaha/base/security/sha256.h b/omaha/base/security/sha256.h index ba5cf33e6..93aa1d1ef 100644 --- a/omaha/base/security/sha256.h +++ b/omaha/base/security/sha256.h @@ -23,11 +23,11 @@ extern "C" { #endif // __cplusplus -typedef HASH_CTX SHA256_CTX; +typedef HASH_CTX LITE_SHA256_CTX; -void SHA256_init(SHA256_CTX* ctx); -void SHA256_update(SHA256_CTX* ctx, const void* data, unsigned int len); -const uint8_t* SHA256_final(SHA256_CTX* ctx); +void SHA256_init(LITE_SHA256_CTX* ctx); +void SHA256_update(LITE_SHA256_CTX* ctx, const void* data, unsigned int len); +const uint8_t* SHA256_final(LITE_SHA256_CTX* ctx); // Convenience method. Returns digest address. const uint8_t* SHA256_hash(const void* data, unsigned int len, uint8_t* digest); diff --git a/omaha/base/security/sha256_unittest.cc b/omaha/base/security/sha256_unittest.cc index 15b8b62d9..1c66900b4 100644 --- a/omaha/base/security/sha256_unittest.cc +++ b/omaha/base/security/sha256_unittest.cc @@ -57,7 +57,7 @@ TEST(Security, Sha256) { for (size_t i = 0; i != arraysize(test_hash256); ++i) { const int len = static_cast(strlen(test_hash256[i].binary)); - SHA256_CTX context = {0}; + LITE_SHA256_CTX context = {0}; SHA256_init(&context); SHA256_update(&context, test_hash256[i].binary, len); const uint8_t* result = SHA256_final(&context); diff --git a/omaha/base/security/testclient.cc b/omaha/base/security/testclient.cc deleted file mode 100644 index 7a7862951..000000000 --- a/omaha/base/security/testclient.cc +++ /dev/null @@ -1,135 +0,0 @@ -// Copyright 2014 Google Inc. -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// ======================================================================== - -#include -#include -#include -#include -#include - -#include "challenger.h" -#include "b64.h" -#include "sha.h" -#include "rsa.h" - -static RSA::PublicKeyInstance kPublicKey = -#include "publickey.h" -; - -int main(int argc, char* argv[]) { - const char* seed = "default seed"; - const char* signature = NULL; - const char* hash = NULL; - const char* input_file = NULL; - const char* encrypt = NULL; - int dochallenge = 0; - int verbose = 0; - - for (int i = 1; i< argc; ++i) { - if (!strcmp(argv[i], "--seed")) seed = argv[++i]; - else if (!strcmp(argv[i], "--signature")) signature = argv[++i]; - else if (!strcmp(argv[i], "--hash")) hash = argv[++i]; - else if (!strcmp(argv[i], "--input_file")) input_file = argv[++i]; - else if (!strcmp(argv[i], "--challenge")) dochallenge = 1; - else if (!strcmp(argv[i], "--verbose")) verbose = 1; - else if (!strcmp(argv[i], "--encrypt")) encrypt = argv[++i]; - else { - fprintf(stderr, "unknown argument '%s'\n", argv[i]); - exit(1); - } - } - - // Construct a Challenger from specified seed, so multiple invocations will - // yield the same challenges. - Challenger challenger(kPublicKey, - reinterpret_cast(seed), - seed?strlen(seed):0); - - const char* challenge = challenger.challenge(); - - if (dochallenge) { - printf("%s", challenge); - return 0; - } - - if (encrypt) { - RSA rsa(kPublicKey); - uint8_t buf[10240]; - int buf_size = rsa.encrypt(reinterpret_cast(encrypt), - strlen(encrypt), - reinterpret_cast(seed), - seed?strlen(seed):0, - buf, sizeof(buf)); - if (buf_size) { - char b64[sizeof(buf) * 2]; - B64_encode(buf, buf_size, b64, sizeof(b64)); - printf("%s", b64); - return 0; - } else { - printf("rsa.encrypt FAILED!"); - return 1; - } - } - - if (verbose) { - printf("seed: %s\n" - "hash: %s\n" - "challenge: %s\n" - "signature: %s\n" - "encrypt: %s\n", - seed, hash, challenge, signature, encrypt); - } - - if (input_file) { - // Hash content of specified input file and compare against provided hash. - FILE* fin = fopen(input_file, "rb"); - if (fin) { - uint8_t buf[64]; - char b64hash[SHA_DIGEST_SIZE * 2]; - SHA_CTX ctx; - int n; - - SHA_init(&ctx); - while ((n = fread(buf, 1, sizeof(buf), fin)) > 0) { - SHA_update(&ctx, buf, n); - } - fclose(fin); - - B64_encode(SHA_final(&ctx), SHA_DIGEST_SIZE, b64hash, sizeof(b64hash)); - - if (hash) { - if (strcmp(hash, b64hash)) { - fprintf(stderr, "hash mismatch: %s vs %s\n", b64hash, hash); - return 1; - } - } - } - } - - if (hash && signature) { - if (!challenger.verify(hash, signature)) { - fprintf(stderr, "failed to verify signature\n"); - return 1; - } else { - // Signature verified. - // We already verified the hash against the file content. - // Done. - - printf("PASS\n"); - } - } - - return 0; -} diff --git a/omaha/base/security/testdata/privatekey.4 b/omaha/base/security/testdata/privatekey.4 deleted file mode 100644 index d6bb1251f..000000000 --- a/omaha/base/security/testdata/privatekey.4 +++ /dev/null @@ -1,15 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIICWwIBAAKBgQCt2tNMMDKsGJppwNVs2JMGx9BaTWUYFj5q5/WkNxqwoOHvM+6n -S8sr9PeGrPriqZhWLGXqsRlC2ZNqxh9TTf8IbnCPt7XSXzsCkX3dfU0OXi6oekdp -4/WmcWg404fTScK+yppw67yU1UKgVqA4nIMP9iEjkvKGXgaysKnPPstdAwIBAwKB -gHPnN4ggIcgQZvErOPM7DK8v4DwzmLq5fvHv+RgkvHXAlp939G+H3Mf4pQRzUexx -EDly7px2ENc7t5yEFOIz/1nalDDOHminC9RTJvslp1rpp9tJh3pjxTDcr+d08kX/ -7Q2WLkmvz25u9YithTetctYwVC1MGtsQRtPlhOHVrLY7AkEA3uWYrG7pnTXoMX77 -hIDtXoGFstswCqv5G62+2TCFSw6CWaNmb7sozvGD4ZPxL8mQRun/4wvwHy50gO0o -qMYlZQJBAMesrdYZS8dzW+NEaUBRGKExWdkhAkOh5Aqynsrr5P7QqA+xm/RKRl/g -z3DEc+iNPma4372+TaZuAFd1U9WCJkcCQQCUmRBy9Ju+I/Ag/1JYVfOUVlkh53Vc -cqYSc9SQywOHXwGRF5mf0hs0oQKWYqDKhmAvRqqXXUq/dE2rSMXF2W5DAkEAhR3J -OWYyhPeSl4Lw1YtlwMuRO2tW18FCscxp3J1DVIsatSESotwu6pXfoIL38F4pmdCV -KSmJGZ6q5PjijlbELwJAVhsTgQDCto8pPUkQyvmPOMtBzNPaYlqcZBmZmrcyVEgV -TQsCb2n3xVp1AwJEm6TSZo8tfRSd6GCEH5grBcntYw== ------END RSA PRIVATE KEY----- diff --git a/omaha/base/security/testdata/publickey.4.h b/omaha/base/security/testdata/publickey.4.h deleted file mode 100644 index 05d0e87fd..000000000 --- a/omaha/base/security/testdata/publickey.4.h +++ /dev/null @@ -1 +0,0 @@ -{4,32,0x04480a55,0x1ae203f1,0x23e95912,0x3630a36f,0x7c800660,0xb9433b1f,0x394322e7,0x297d3f11,0xcca3e481,0x40dd4037,0xf7bf42d8,0x5fed9e7c,0xe2b2b824,0x3d03e10c,0xaeb8b3c9,0x6ee6473f,0x4fe45331,0x5b7f3184,0x2c54183e,0x99037f01,0xd864b9d2,0x681472ab,0x01cf82fb,0x95e6b62c,0x98c1c41b,0x6ed0463e,0x0e7cc820,0x4993bc27,0xb8fdc1b6,0x004b2e9b,0xb58730a0,0xb2af3930,0xbbc15687,0x3ca95bb7,0x16a4a351,0x5ca051af,0x36ca7470,0x65ef3443,0x4b2a0e96,0x272cd317,0x2eff92d3,0xdb34bfbe,0x1fade9da,0xe01638d3,0x14e14dd9,0xf16c562e,0xb5df74fd,0xb07ca6fd,0x31728cf1,0xb5014e59,0x82196247,0x067005dd,0x6477efc7,0xd8dd44e8,0x8c3ad156,0x52338009,0x759cda44,0x7be9d442,0xf0eebec4,0x13ffd17b,0x8669ef5a,0x4ab27426,0xe58037f2,0x705b8d2c,0x3d7f4620} diff --git a/omaha/base/signatures.cc b/omaha/base/signatures.cc index 444f95026..8804b2897 100644 --- a/omaha/base/signatures.cc +++ b/omaha/base/signatures.cc @@ -151,7 +151,7 @@ class SHA256Hash : public HashInterface { } private: - SHA256_CTX ctx2_; + LITE_SHA256_CTX ctx2_; DISALLOW_COPY_AND_ASSIGN(SHA256Hash); }; diff --git a/omaha/client/install.cc b/omaha/client/install.cc index 32941f2a9..7bfac754f 100644 --- a/omaha/client/install.cc +++ b/omaha/client/install.cc @@ -625,6 +625,7 @@ void HandleInstallError(HRESULT error, if (is_eula_required || is_oem_install || is_enterprise_install) { return; } + Ping ping(is_machine, session_id, install_source); ping.LoadAppDataFromExtraArgs(extra_args); if (!has_setup_succeeded) { @@ -646,9 +647,10 @@ void HandleInstallError(HRESULT error, extra_code1)); ping.BuildAppsPing(install_complete_ping_event); } + HRESULT hr = ping.Send(false); if (FAILED(hr)) { - CORE_LOG(LW, (_T("[Ping::Send failed][0x%x]"), hr)); + CORE_LOG(LW, (_T("[ping.Send failed][0x%x]"), hr)); } } diff --git a/omaha/client/install_apps.cc b/omaha/client/install_apps.cc index 1b8cf3282..fe1d7e91c 100644 --- a/omaha/client/install_apps.cc +++ b/omaha/client/install_apps.cc @@ -494,9 +494,9 @@ void HandleInstallAppsError(HRESULT error, error, extra_code1)); ping.BuildAppsPing(ping_event); - HRESULT send_result = ping.Send(true); + HRESULT send_result = SendReliablePing(&ping, true); if (FAILED(send_result)) { - CORE_LOG(LW, (_T("[Ping::Send failed][0x%x]"), send_result)); + CORE_LOG(LW, (_T("[SendReliablePing failed][0x%x]"), send_result)); } } diff --git a/omaha/client/install_self.cc b/omaha/client/install_self.cc index dd020677e..2afc254f5 100644 --- a/omaha/client/install_self.cc +++ b/omaha/client/install_self.cc @@ -369,9 +369,9 @@ HRESULT InstallSelf(bool is_machine, install_ping.BuildOmahaPing(current_version, next_version, setup_install_complete_ping_event); - HRESULT send_result = install_ping.Send(true); + HRESULT send_result = SendReliablePing(&install_ping, true); if (FAILED(send_result)) { - CORE_LOG(LW, (_T("[InstallPing::Send failed][0x%x]"), send_result)); + CORE_LOG(LW, (_T("[SendReliablePing failed][%#x]"), send_result)); } return S_OK; @@ -396,6 +396,9 @@ HRESULT UpdateSelf(bool is_machine, const CString& session_id) { CORE_LOG(LE, (_T("[DoSelfUpdate failed][0x%08x]"), hr)); } + metric_omaha_last_error_code = hr; + metric_omaha_last_extra_code = extra_code1; + // If a self-update failed because an uninstall of that Omaha is in progress, // don't bother with an update failure ping; the uninstall ping will suffice. if (hr == GOOPDATE_E_FAILED_TO_GET_LOCK_UNINSTALL_PROCESS_RUNNING) { @@ -421,7 +424,7 @@ HRESULT UpdateSelf(bool is_machine, const CString& session_id) { ping.BuildOmahaPing(current_version, next_version, update_complete_ping_event); - ping.Send(false); + SendReliablePing(&ping, false); return hr; } diff --git a/omaha/common/app_registry_utils.cc b/omaha/common/app_registry_utils.cc index bdf11cc9c..be3a3f46f 100644 --- a/omaha/common/app_registry_utils.cc +++ b/omaha/common/app_registry_utils.cc @@ -416,6 +416,7 @@ void GetAppLang(bool is_machine, const CString& app_id, CString* lang) { // client // iid // experiment +// cohort // Reads InstallTime and computes InstallTimeDiffSec. void GetClientStateData(bool is_machine, const CString& app_id, @@ -426,6 +427,7 @@ void GetClientStateData(bool is_machine, CString* client_id, CString* iid, CString* experiment_labels, + Cohort* cohort, int* install_time_diff_sec, int* day_of_install) { RegKey key; @@ -457,6 +459,9 @@ void GetClientStateData(bool is_machine, if (experiment_labels) { key.GetValue(kRegValueExperimentLabels, experiment_labels); } + if (cohort) { + ReadCohort(is_machine, app_id, cohort); + } if (install_time_diff_sec) { *install_time_diff_sec = GetInstallTimeDiffSec(is_machine, app_id); } @@ -514,6 +519,66 @@ HRESULT GetDayOfInstall( return S_OK; } +CString GetCohortKeyName(bool is_machine, const CString& app_id) { + const CString app_id_key_name(GetAppClientStateKey(is_machine, app_id)); + return AppendRegKeyPath(app_id_key_name, kRegSubkeyCohort); +} + +HRESULT DeleteCohortKey(bool is_machine, const CString& app_id) { + return RegKey::DeleteKey(GetCohortKeyName(is_machine, app_id)); +} + +HRESULT ReadCohort(bool is_machine, const CString& app_id, Cohort* cohort) { + CORE_LOG(L3, (_T("[ReadCohort][%s]"), app_id)); + ASSERT1(cohort); + + RegKey cohort_key; + HRESULT hr = cohort_key.Open(GetCohortKeyName(is_machine, app_id), KEY_READ); + if (FAILED(hr)) { + return hr; + } + + hr = cohort_key.GetValue(NULL, &cohort->cohort); + if (FAILED(hr)) { + return hr; + } + + // Optional values. + cohort_key.GetValue(kRegValueCohortHint, &cohort->hint); + cohort_key.GetValue(kRegValueCohortName, &cohort->name); + + CORE_LOG(L3, (_T("[ReadCohort][%s][%s][%s]"), cohort->cohort, + cohort->hint, + cohort->name)); + return S_OK; +} + +HRESULT WriteCohort(bool is_machine, + const CString& app_id, + const Cohort& cohort) { + CORE_LOG(L3, (_T("[WriteCohort][%s]"), cohort.cohort)); + + if (cohort.cohort.IsEmpty()) { + return DeleteCohortKey(is_machine, app_id); + } + + RegKey cohort_key; + HRESULT hr = cohort_key.Create(GetCohortKeyName(is_machine, app_id)); + if (FAILED(hr)) { + return hr; + } + + hr = cohort_key.SetValue(NULL, cohort.cohort); + if (FAILED(hr)) { + return hr; + } + + VERIFY1(SUCCEEDED(cohort_key.SetValue(kRegValueCohortHint, cohort.hint))); + VERIFY1(SUCCEEDED(cohort_key.SetValue(kRegValueCohortName, cohort.name))); + + return S_OK; +} + HRESULT GetUninstalledApps(bool is_machine, std::vector* app_ids) { ASSERT1(app_ids); diff --git a/omaha/common/app_registry_utils.h b/omaha/common/app_registry_utils.h index 219d387f2..ddd7458e0 100644 --- a/omaha/common/app_registry_utils.h +++ b/omaha/common/app_registry_utils.h @@ -28,6 +28,12 @@ namespace omaha { +struct Cohort { + CString cohort; // Opaque string. + CString hint; // Server may use to move the app to a new cohort. + CString name; // Human-readable interpretation of the cohort. +}; + namespace app_registry_utils { // Returns the application registration path for the specified app. @@ -118,6 +124,7 @@ void GetClientStateData(bool is_machine, CString* client_id, CString* iid, CString* experiment_labels, + Cohort* cohort, int* install_time_diff_sec, int* day_of_install); @@ -129,6 +136,13 @@ HRESULT GetDayOfInstall(bool is_machine, const CString& app_id, DWORD* day_of_install); +CString GetCohortKeyName(bool is_machine, const CString& app_id); +HRESULT DeleteCohortKey(bool is_machine, const CString& app_id); +HRESULT ReadCohort(bool is_machine, const CString& app_id, Cohort* cohort); +HRESULT WriteCohort(bool is_machine, + const CString& app_id, + const Cohort& cohort); + // Reads all uninstalled apps from the registry. HRESULT GetUninstalledApps(bool is_machine, std::vector* app_ids); diff --git a/omaha/common/app_registry_utils_unittest.cc b/omaha/common/app_registry_utils_unittest.cc index 62e8112ae..b2eb798a6 100644 --- a/omaha/common/app_registry_utils_unittest.cc +++ b/omaha/common/app_registry_utils_unittest.cc @@ -121,7 +121,8 @@ TEST(AppRegistryUtilsTest, GetAppClientStateMediumKey_UserAndMachineAreSame) { GetAppClientStateMediumKey(false, kAppGuid1)); } -class AppRegistryUtilsRegistryProtectedTest : public testing::Test { +class AppRegistryUtilsRegistryProtectedTest : + public ::testing::TestWithParam { protected: AppRegistryUtilsRegistryProtectedTest() : hive_override_key_name_(kRegistryHiveOverrideRoot) { @@ -138,6 +139,15 @@ class AppRegistryUtilsRegistryProtectedTest : public testing::Test { RestoreRegistryHives(); ASSERT_SUCCEEDED(RegKey::DeleteKey(hive_override_key_name_, true)); } + + const bool IsMachine() { + return GetParam(); + } + + const CString GetClientStatePath() { + return IsMachine() ? kOmahaMachineClientStatePath : + kOmahaUserClientStatePath; + } }; TEST_F(AppRegistryUtilsRegistryProtectedTest, @@ -2460,8 +2470,11 @@ TEST_F(AppRegistryUtilsRegistryProtectedTest, GetAppLang_Machine) { EXPECT_STREQ(expected_lang, actual_lang); } -TEST_F(AppRegistryUtilsRegistryProtectedTest, - GetClientStateData_User) { +INSTANTIATE_TEST_CASE_P(IsMachine, + AppRegistryUtilsRegistryProtectedTest, + ::testing::Bool()); + +TEST_P(AppRegistryUtilsRegistryProtectedTest, GetClientStateData) { const CString expected_pv = _T("1.0"); const CString expected_ap = _T("additional parameters"); const CString expected_lang = _T("some lang"); @@ -2471,119 +2484,55 @@ TEST_F(AppRegistryUtilsRegistryProtectedTest, _T("{7C0B6E56-B24B-436b-A960-A6EA201E886F}"); const CString expected_experiment_label = _T("some_experiment=a|Fri, 14 Aug 2015 16:13:03 GMT"); + const Cohort expected_cohort = { + _T("Cohort1"), + _T("CohortHint1"), + _T("CohortName1") + }; const int day_of_install = 2677; - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaUserClientStatePath, + EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(GetClientStatePath(), kRegValueProductVersion, expected_pv)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaUserClientStatePath, + EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(GetClientStatePath(), kRegValueAdditionalParams, expected_ap)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaUserClientStatePath, + EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(GetClientStatePath(), kRegValueLanguage, expected_lang)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaUserClientStatePath, + EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(GetClientStatePath(), kRegValueBrandCode, expected_brand_code)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaUserClientStatePath, + EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(GetClientStatePath(), kRegValueClientId, expected_client_id)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaUserClientStatePath, + EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(GetClientStatePath(), kRegValueInstallationId, expected_iid)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaUserClientStatePath, + EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(GetClientStatePath(), kRegValueExperimentLabels, expected_experiment_label)); + EXPECT_HRESULT_SUCCEEDED(WriteCohort(IsMachine(), + kGoogleUpdateAppId, + expected_cohort)); EXPECT_HRESULT_SUCCEEDED( - RegKey::SetValue(kOmahaUserClientStatePath, + RegKey::SetValue(GetClientStatePath(), kRegValueDayOfInstall, static_cast(day_of_install))); const DWORD now = Time64ToInt32(GetCurrent100NSTime()); const DWORD one_day_back = now - kSecondsPerDay; - ASSERT_SUCCEEDED(RegKey::SetValue(kOmahaUserClientStatePath, + ASSERT_SUCCEEDED(RegKey::SetValue(GetClientStatePath(), kRegValueInstallTimeSec, one_day_back)); CString actual_pv, actual_ap, actual_lang, actual_brand_code, actual_client_id, actual_experiment_label, actual_iid; + Cohort actual_cohort; int actual_day_of_install(0); int actual_install_time_diff_sec(0); - GetClientStateData(false, - kGoogleUpdateAppId, - &actual_pv, - &actual_ap, - &actual_lang, - &actual_brand_code, - &actual_client_id, - &actual_iid, - &actual_experiment_label, - &actual_install_time_diff_sec, - &actual_day_of_install); - - EXPECT_STREQ(expected_pv, actual_pv); - EXPECT_STREQ(expected_ap, actual_ap); - EXPECT_STREQ(expected_lang, actual_lang); - EXPECT_STREQ(expected_brand_code, actual_brand_code); - EXPECT_STREQ(expected_client_id, actual_client_id); - EXPECT_STREQ(expected_iid, actual_iid); - EXPECT_STREQ(expected_experiment_label, actual_experiment_label); - EXPECT_EQ(GetFirstDayOfWeek(day_of_install), actual_day_of_install); - EXPECT_GE(actual_install_time_diff_sec, kSecondsPerDay); -} - -TEST_F(AppRegistryUtilsRegistryProtectedTest, - GetGoogleUpdatePersistentData_Machine) { - const CString expected_pv = _T("1.0"); - const CString expected_ap = _T("additional parameters"); - const CString expected_lang = _T("some lang"); - const CString expected_brand_code = _T("some brand"); - const CString expected_client_id = _T("some client id"); - const CString expected_iid = - _T("{7C0B6E56-B24B-436b-A960-A6EA201E886F}"); - const CString expected_experiment_label = - _T("some_experiment=a|Fri, 14 Aug 2015 16:13:03 GMT"); - const int day_of_install = 3377; - - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaMachineClientStatePath, - kRegValueProductVersion, - expected_pv)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaMachineClientStatePath, - kRegValueAdditionalParams, - expected_ap)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaMachineClientStatePath, - kRegValueLanguage, - expected_lang)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaMachineClientStatePath, - kRegValueBrandCode, - expected_brand_code)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaMachineClientStatePath, - kRegValueClientId, - expected_client_id)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaMachineClientStatePath, - kRegValueInstallationId, - expected_iid)); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(kOmahaMachineClientStatePath, - kRegValueExperimentLabels, - expected_experiment_label)); - EXPECT_HRESULT_SUCCEEDED( - RegKey::SetValue(kOmahaMachineClientStatePath, - kRegValueDayOfInstall, - static_cast(day_of_install))); - - const DWORD now = Time64ToInt32(GetCurrent100NSTime()); - const DWORD one_day_back = now - kSecondsPerDay; - ASSERT_SUCCEEDED(RegKey::SetValue(kOmahaMachineClientStatePath, - kRegValueInstallTimeSec, - one_day_back)); - - CString actual_pv, actual_ap, actual_lang, actual_brand_code, - actual_client_id, actual_experiment_label, actual_iid; - int actual_day_of_install(0); - int actual_install_time_diff_sec(0); - - GetClientStateData(true, + GetClientStateData(IsMachine(), kGoogleUpdateAppId, &actual_pv, &actual_ap, @@ -2592,6 +2541,7 @@ TEST_F(AppRegistryUtilsRegistryProtectedTest, &actual_client_id, &actual_iid, &actual_experiment_label, + &actual_cohort, &actual_install_time_diff_sec, &actual_day_of_install); @@ -2602,6 +2552,9 @@ TEST_F(AppRegistryUtilsRegistryProtectedTest, EXPECT_STREQ(expected_client_id, actual_client_id); EXPECT_STREQ(expected_iid, actual_iid); EXPECT_STREQ(expected_experiment_label, actual_experiment_label); + EXPECT_STREQ(expected_cohort.cohort, actual_cohort.cohort); + EXPECT_STREQ(expected_cohort.hint, actual_cohort.hint); + EXPECT_STREQ(expected_cohort.name, actual_cohort.name); EXPECT_EQ(GetFirstDayOfWeek(day_of_install), actual_day_of_install); EXPECT_GE(actual_install_time_diff_sec, kSecondsPerDay); } diff --git a/omaha/common/config_manager.cc b/omaha/common/config_manager.cc index b8043c19f..56433b921 100644 --- a/omaha/common/config_manager.cc +++ b/omaha/common/config_manager.cc @@ -39,6 +39,7 @@ #include "omaha/common/const_goopdate.h" #include "omaha/common/crash_utils.h" #include "omaha/common/oem_install_utils.h" +#include "omaha/statsreport/metrics.h" namespace omaha { @@ -561,13 +562,17 @@ HRESULT ConfigManager::SetRetryAfterTime(bool is_machine, DWORD time) const { bool ConfigManager::CanRetryNow(bool is_machine) const { const uint32 now = Time64ToInt32(GetCurrent100NSTime()); const uint32 retry_after = GetRetryAfterTime(is_machine); - return now >= retry_after; + + const int kMaxRetryAfterSeconds = kSecondsPerDay; + return now >= retry_after || retry_after > now + kMaxRetryAfterSeconds; } +DEFINE_METRIC_integer(last_started_au); HRESULT ConfigManager::SetLastStartedAU(bool is_machine) const { const TCHAR* reg_update_key = is_machine ? MACHINE_REG_UPDATE: USER_REG_UPDATE; DWORD now = Time64ToInt32(GetCurrent100NSTime()); + metric_last_started_au = now; return RegKey::SetValue(reg_update_key, kRegValueLastStartedAU, now); } diff --git a/omaha/common/config_manager_unittest.cc b/omaha/common/config_manager_unittest.cc index 86ac06825..189576c22 100644 --- a/omaha/common/config_manager_unittest.cc +++ b/omaha/common/config_manager_unittest.cc @@ -1753,6 +1753,13 @@ TEST_P(ConfigManagerTest, CanRetryNow) { EXPECT_SUCCEEDED(cm_->SetRetryAfterTime(false, now + kSecondsPerHour)); EXPECT_FALSE(cm_->CanRetryNow(false)); + + EXPECT_SUCCEEDED(cm_->SetRetryAfterTime(false, now + 2 * kSecondsPerDay)); + EXPECT_TRUE(cm_->CanRetryNow(false)); + + EXPECT_SUCCEEDED(cm_->SetRetryAfterTime(false, + std::numeric_limits::max())); + EXPECT_TRUE(cm_->CanRetryNow(false)); } // Tests GetDir indirectly. diff --git a/omaha/common/goopdate_utils.cc b/omaha/common/goopdate_utils.cc index d4325e293..0cb540999 100644 --- a/omaha/common/goopdate_utils.cc +++ b/omaha/common/goopdate_utils.cc @@ -1442,10 +1442,13 @@ HRESULT WriteInstallerDataToTempFile(const CString& installer_data, return S_OK; } +DEFINE_METRIC_integer(last_checked); HRESULT UpdateLastChecked(bool is_machine) { // Set the last check value to the current value. DWORD now = Time64ToInt32(GetCurrent100NSTime()); CORE_LOG(L3, (_T("[UpdateLastChecked][now %d]"), now)); + + metric_last_checked = now; HRESULT hr = ConfigManager::Instance()->SetLastCheckedTime(is_machine, now); if (FAILED(hr)) { CORE_LOG(LE, (_T("[SetLastCheckedTime failed][0x%08x]"), hr)); diff --git a/omaha/common/ping.cc b/omaha/common/ping.cc index b2b56a03d..4ef2e39ba 100644 --- a/omaha/common/ping.cc +++ b/omaha/common/ping.cc @@ -18,10 +18,12 @@ #include "omaha/base/constants.h" #include "omaha/base/debug.h" #include "omaha/base/logging.h" +#include "omaha/base/scope_guard.h" #include "omaha/base/scoped_any.h" #include "omaha/base/scoped_impersonation.h" #include "omaha/base/string.h" #include "omaha/base/utils.h" +#include "omaha/base/vistautil.h" #include "omaha/base/vista_utils.h" #include "omaha/common/app_registry_utils.h" #include "omaha/common/command_line.h" @@ -38,8 +40,11 @@ namespace omaha { -const TCHAR* const Ping::kRegKeyPing = _T("Pings"); -const time64 Ping::kPingExpiry100ns = 10 * kDaysTo100ns; // 10 days. +const TCHAR* const Ping::kRegKeyPersistedPings = _T("PersistedPings"); +const TCHAR* const Ping::kRegValuePersistedPingTime = _T("PersistedPingTime"); +const TCHAR* const Ping::kRegValuePersistedPingString = + _T("PersistedPingString"); +const time64 Ping::kPersistedPingExpiry100ns = 10 * kDaysTo100ns; // 10 days. // Minimum compatible Omaha version that understands the /ping command line. // 1.3.0.0. @@ -47,12 +52,31 @@ const ULONGLONG kMinOmahaVersionForPingOOP = 0x0001000300000000; Ping::Ping(bool is_machine, const CString& session_id, - const CString& install_source) - : is_machine_(is_machine), - ping_request_(xml::UpdateRequest::Create(is_machine, - session_id, - install_source, - CString())) { + const CString& install_source, + const CString& request_id) { + Initialize(is_machine, session_id, install_source, request_id); +} + +Ping::Ping(bool is_machine, + const CString& session_id, + const CString& install_source) { + CString request_id; + VERIFY1(SUCCEEDED(GetGuid(&request_id))); + Initialize(is_machine, session_id, install_source, request_id); +} + +void Ping::Initialize(bool is_machine, + const CString& session_id, + const CString& install_source, + const CString& request_id) { + is_machine_ = is_machine; + request_id_ = request_id; + + ping_request_.reset(xml::UpdateRequest::Create(is_machine, + session_id, + install_source, + CString(), + request_id)); CString shell_version_string = goopdate_utils::GetInstalledShellVersion(is_machine); if (!shell_version_string.IsEmpty()) { @@ -100,6 +124,7 @@ void Ping::LoadOmahaDataFromRegistry() { &omaha_data_.client_id, &omaha_data_.installation_id, &omaha_data_.experiment_labels, + &omaha_data_.cohort, &omaha_data_.install_time_diff_sec, &omaha_data_.day_of_install); } @@ -118,6 +143,7 @@ void Ping::LoadAppDataFromRegistry(const std::vector& app_ids) { &app_data.client_id, &app_data.installation_id, &app_data.experiment_labels, + &app_data.cohort, &app_data.install_time_diff_sec, &app_data.day_of_install); apps_data_.push_back(app_data); @@ -145,13 +171,22 @@ HRESULT Ping::Send(bool is_fire_and_forget) { ASSERT1(ConfigManager::Instance()->CanUseNetwork(is_machine_)); + // When the ping is sent successfully, the ScopeGuard ensures that the + // corresponding persisted ping is deleted. In failure cases, the persisted + // ping is retained to be sent in a subsequent UA run. + HRESULT hr = E_FAIL; + ON_SCOPE_EXIT_OBJ(*this, + &Ping::DeletePersistedPingOnSuccess, + ByRef(hr)); + if (ping_request_->IsEmpty()) { CORE_LOG(L3, (_T("[Ping::Send did not send empty ping]"))); - return S_FALSE; + hr = S_FALSE; + return hr; } CString request_string; - HRESULT hr = BuildRequestString(&request_string); + hr = BuildRequestString(&request_string); if (FAILED(hr)) { CORE_LOG(LE, (_T("[BuildRequestString failed][0x%08x]"), hr)); return hr; @@ -172,7 +207,7 @@ HRESULT Ping::Send(bool is_fire_and_forget) { CORE_LOG(LE, (_T("[Ping::SendInProcess failed][0x%x]"), hr)); - return PersistPing(is_machine_, request_string); + return hr; } void Ping::BuildOmahaPing(const CString& version, @@ -205,6 +240,9 @@ xml::request::App Ping::BuildOmahaApp(const CString& version, app.iid = omaha_data_.installation_id; app.install_time_diff_sec = omaha_data_.install_time_diff_sec; app.day_of_install = omaha_data_.day_of_install; + app.cohort = omaha_data_.cohort.cohort; + app.cohort_hint = omaha_data_.cohort.hint; + app.cohort_name = omaha_data_.cohort.name; app.version = version; app.next_version = next_version; @@ -212,22 +250,6 @@ xml::request::App Ping::BuildOmahaApp(const CString& version, return app; } -void Ping::BuildAppPing(const CString& app_id, - const CString& version, - const CString& next_version, - const CString& client_id, - const PingEventPtr& ping_event) { - xml::request::App app; - - app.app_id = app_id; - app.version = version; - app.next_version = next_version; - app.client_id = client_id; - - app.ping_events.push_back(ping_event); - ping_request_->AddApp(app); -} - void Ping::BuildAppsPing(const PingEventPtr& ping_event) { for (size_t i = 0; i != apps_data_.size(); ++i) { xml::request::App app; @@ -241,6 +263,9 @@ void Ping::BuildAppsPing(const PingEventPtr& ping_event) { app.iid = apps_data_[i].installation_id; app.install_time_diff_sec = apps_data_[i].install_time_diff_sec; app.day_of_install = apps_data_[i].day_of_install; + app.cohort = apps_data_[i].cohort.cohort; + app.cohort_hint = apps_data_[i].cohort.hint; + app.cohort_name = apps_data_[i].cohort.name; app.ping_events.push_back(ping_event); ping_request_->AddApp(app); @@ -309,27 +334,49 @@ HRESULT Ping::BuildRequestString(CString* request_string) const { return ping_request_->Serialize(request_string); } -CString Ping::GetPingRegPath(bool is_machine) { - CString ping_reg_path = is_machine ? MACHINE_REG_UPDATE : USER_REG_UPDATE; - return AppendRegKeyPath(ping_reg_path, kRegKeyPing); +CString Ping::GetPersistedPingsRegPath(bool is_machine) { + CString persisted_pings_reg_path = is_machine ? MACHINE_REG_UPDATE : + USER_REG_UPDATE; + return AppendRegKeyPath(persisted_pings_reg_path, kRegKeyPersistedPings); } -HRESULT Ping::LoadPersistedPings(bool is_machine, PingsVector* pings) { - ASSERT1(pings); +HRESULT Ping::LoadPersistedPings(bool is_machine, + PingsVector* persisted_pings) { + ASSERT1(persisted_pings); - RegKey ping_reg_key; - HRESULT hr = ping_reg_key.Open(GetPingRegPath(is_machine), KEY_READ); + RegKey persisted_pings_reg_key; + CString persisted_pings_reg_path(GetPersistedPingsRegPath(is_machine)); + HRESULT hr = persisted_pings_reg_key.Open(persisted_pings_reg_path, KEY_READ); if (FAILED(hr)) { - CORE_LOG(LW, (_T("[Unable to open Ping regkey][0x%x]"), hr)); + CORE_LOG(LW, (_T("[Unable to open Persisted pings regkey][%#x]"), hr)); return hr; } - int num_pings = ping_reg_key.GetValueCount(); + int num_pings = persisted_pings_reg_key.GetSubkeyCount(); for (int i = 0; i < num_pings; ++i) { + CString persisted_subkey_name; + hr = persisted_pings_reg_key.GetSubkeyNameAt(i, &persisted_subkey_name); + if (FAILED(hr)) { + CORE_LOG(LW, (_T("[GetSubkeyNameAt failed][%d]"), i)); + continue; + } + + RegKey persisted_ping_reg_key; + CString persisted_ping_reg_path( + AppendRegKeyPath(persisted_pings_reg_path, persisted_subkey_name)); + hr = persisted_ping_reg_key.Open(persisted_ping_reg_path, KEY_READ); + if (FAILED(hr)) { + CORE_LOG(LW, (_T("[Unable to open Persisted Ping subkey][%s][%#x]"), + persisted_subkey_name, hr)); + continue; + } + CString persisted_time_string; - hr = ping_reg_key.GetValueNameAt(i, &persisted_time_string, NULL); + hr = persisted_ping_reg_key.GetValue(kRegValuePersistedPingTime, + &persisted_time_string); if (FAILED(hr)) { - CORE_LOG(LW, (_T("[GetValueNameAt failed][%d]"), i)); + CORE_LOG(LW, (_T("[GetValue kRegValuePersistedPingTime failed][%#x]"), + hr)); continue; } @@ -339,14 +386,22 @@ HRESULT Ping::LoadPersistedPings(bool is_machine, PingsVector* pings) { continue; } - CString ping_string; - hr = ping_reg_key.GetValue(persisted_time_string, &ping_string); + CString persisted_ping_string; + hr = persisted_ping_reg_key.GetValue(kRegValuePersistedPingString, + &persisted_ping_string); if (FAILED(hr)) { - CORE_LOG(LW, (_T("[GetValue failed][%s]"), persisted_time_string)); + CORE_LOG(LW, (_T("[GetValue kRegValuePersistedPingString failed][%#x]"), + hr)); continue; } - pings->push_back(std::make_pair(persisted_time, ping_string)); + persisted_pings->push_back(std::make_pair( + persisted_subkey_name, + std::make_pair(persisted_time, persisted_ping_string))); + CORE_LOG(L6, (_T("[Persisted ping][%s][%s][%s]"), + persisted_subkey_name, + persisted_time_string, + persisted_ping_string)); } return S_OK; @@ -365,62 +420,116 @@ bool Ping::IsPingExpired(time64 persisted_time) { CORE_LOG(L3, (_T("[%I64u][%I64u][%I64u]"), now, persisted_time, time_difference)); - const bool result = time_difference >= kPingExpiry100ns; + const bool result = time_difference >= kPersistedPingExpiry100ns; CORE_LOG(L3, (_T("[IsPingExpired][%d]"), result)); return result; } -HRESULT Ping::DeletePersistedPing(bool is_machine, time64 persisted_time) { - CString persisted_time_string; - persisted_time_string.Format(_T("%I64u"), persisted_time); - CORE_LOG(L3, (_T("[Ping::DeletePersistedPing][%s]"), persisted_time_string)); +HRESULT Ping::DeletePersistedPing(bool is_machine, + const CString& persisted_subkey_name) { + CORE_LOG(L3, (_T("[Ping::DeletePersistedPing][%s]"), persisted_subkey_name)); - CString ping_reg_path(GetPingRegPath(is_machine)); - HRESULT hr = RegKey::DeleteValue(ping_reg_path, persisted_time_string); + CString persisted_pings_reg_path(GetPersistedPingsRegPath(is_machine)); + CString persisted_ping_reg_path = AppendRegKeyPath(persisted_pings_reg_path, + persisted_subkey_name); - if (RegKey::IsKeyEmpty(ping_reg_path)) { - VERIFY1(SUCCEEDED(RegKey::DeleteKey(ping_reg_path))); + if (!RegKey::HasKey(persisted_ping_reg_path)) { + return S_OK; } - return hr; + // Registry writes to HKLM need admin. + scoped_revert_to_self revert_to_self; + + return RegKey::DeleteKey(persisted_ping_reg_path); +} + +void Ping::DeletePersistedPingOnSuccess(const HRESULT& hr) { + if (SUCCEEDED(hr)) { + VERIFY1(SUCCEEDED(DeletePersistedPing(is_machine_, request_id_))); + } +} + +CString Ping::GetPersistedPingRegPath() { + return AppendRegKeyPath(GetPersistedPingsRegPath(is_machine_), request_id_); } -HRESULT Ping::PersistPing(bool is_machine, const CString& ping_string) { +HRESULT Ping::PersistPing() { + CString ping_string; + HRESULT hr = BuildRequestString(&ping_string); + if (FAILED(hr)) { + CORE_LOG(LE, (_T("[PersistPing][BuildRequestString failed][%#x]"), hr)); + return hr; + } + CString time_now_str; time_now_str.Format(_T("%I64u"), GetCurrent100NSTime()); - CORE_LOG(L3, (_T("[Ping::PersistPing][%s][%s]"), time_now_str, ping_string)); + CORE_LOG(L3, (_T("[Ping::PersistPing][%s][%s][%s]"), + request_id_, time_now_str, ping_string)); - return RegKey::SetValue(GetPingRegPath(is_machine), - time_now_str, - ping_string); + CString ping_reg_path(GetPersistedPingRegPath()); + + // Registry writes to HKLM need admin. + scoped_revert_to_self revert_to_self; + ASSERT1(!is_machine_ || vista_util::IsUserAdmin()); + + hr = RegKey::SetValue(ping_reg_path, + kRegValuePersistedPingString, + ping_string); + if (FAILED(hr)) { + return hr; + } + + return RegKey::SetValue(ping_reg_path, + kRegValuePersistedPingTime, + time_now_str); } HRESULT Ping::SendPersistedPings(bool is_machine) { - PingsVector pings; - HRESULT hr = LoadPersistedPings(is_machine, &pings); + PingsVector persisted_pings; + HRESULT hr = LoadPersistedPings(is_machine, &persisted_pings); if (FAILED(hr) && (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))) { return hr; } - for (size_t i = 0; i != pings.size(); ++i) { - time64 persisted_time = pings[i].first; + scoped_handle impersonation_token; + hr = vista::GetLoggedOnUserToken(address(impersonation_token)); + if (FAILED(hr)) { + CORE_LOG(LE, (_T("[SendPersistedPings][GetLoggedOnUserToken failed][%#x]"), + hr)); + // Continue anyway. + } + + scoped_impersonation impersonate_user(get(impersonation_token)); + hr = HRESULT_FROM_WIN32(impersonate_user.result()); + if (FAILED(hr)) { + CORE_LOG(LE, (_T("[SendPersistedPings][impersonation failed][%#x]"), hr)); + // Continue anyway. + } + + for (size_t i = 0; i != persisted_pings.size(); ++i) { + const CString& persisted_subkey_name(persisted_pings[i].first); + time64 persisted_time = persisted_pings[i].second.first; int32 request_age = Time64ToInt32(GetCurrent100NSTime()) - Time64ToInt32(persisted_time); - const CString& ping_string(pings[i].second); + const CString& persisted_ping_string(persisted_pings[i].second.second); - CORE_LOG(L3, (_T("[Resending ping][%I64u][%d][%s]"), - persisted_time, request_age, ping_string)); + CORE_LOG(L3, (_T("[Resending persisted ping][%s][%I64u][%d][%s]"), + persisted_subkey_name, + persisted_time, + request_age, + persisted_ping_string)); CString request_age_string; request_age_string.Format(_T("%d"), request_age); HeadersVector headers; headers.push_back(std::make_pair(kHeaderXRequestAge, request_age_string)); - hr = SendString(is_machine, headers, ping_string); + hr = SendString(is_machine, headers, persisted_ping_string); if (SUCCEEDED(hr) || IsPingExpired(persisted_time)) { - CORE_LOG(L3, (_T("[Deleting ping][0x%x]"), hr)); - VERIFY1(SUCCEEDED(DeletePersistedPing(is_machine, persisted_time))); + CORE_LOG(L3, (_T("[Deleting persisted ping][0x%x]"), hr)); + VERIFY1(SUCCEEDED(DeletePersistedPing(is_machine, + persisted_subkey_name))); } } @@ -495,5 +604,13 @@ HRESULT Ping::HandlePing(bool is_machine, const CString& ping_string) { Utf8ToWideChar(request_string_utf8, request_string_utf8.GetLength())); } +HRESULT SendReliablePing(Ping* ping, bool is_fire_and_forget) { + CORE_LOG(L6, (_T("[Ping::SendReliablePing]"))); + ASSERT1(ping); + + VERIFY1(SUCCEEDED(ping->PersistPing())); + return ping->Send(is_fire_and_forget); +} + } // namespace omaha diff --git a/omaha/common/ping.h b/omaha/common/ping.h index 7d1c58437..a79b25f2e 100644 --- a/omaha/common/ping.h +++ b/omaha/common/ping.h @@ -67,6 +67,7 @@ #include "base/basictypes.h" #include "base/scoped_ptr.h" #include "gtest/gtest_prod.h" +#include "omaha/common/app_registry_utils.h" #include "omaha/common/ping_event.h" #include "omaha/common/update_request.h" #include "omaha/common/web_services_client.h" @@ -89,6 +90,10 @@ class App; // sent from the setup, before any model object could be created. class Ping { public: + Ping(bool is_machine, + const CString& session_id, + const CString& install_source, + const CString& request_id); Ping(bool is_machine, const CString& session_id, const CString& install_source); @@ -119,12 +124,6 @@ class Ping { void BuildAppsPing(const PingEventPtr& ping_event); - void BuildAppPing(const CString& app_id, - const CString& version, - const CString& next_version, - const CString& client_id, - const PingEventPtr& ping_event); - // Serializes a ping request as a string. HRESULT BuildRequestString(CString* request_string) const; @@ -149,6 +148,9 @@ class Ping { // mechanism. HRESULT Send(bool is_fire_and_forget); + // Persists the current Ping object to the registry. + HRESULT PersistPing(); + // Sends all persisted pings. Deletes successful or expired pings. static HRESULT SendPersistedPings(bool is_machine); @@ -167,16 +169,25 @@ class Ping { FRIEND_TEST(PingTest, IsPingExpired_CurrentTime); FRIEND_TEST(PingTest, IsPingExpired_FutureTime); FRIEND_TEST(PingTest, LoadPersistedPings_NoPersistedPings); - FRIEND_TEST(PingTest, LoadPersistedPings); + FRIEND_TEST(PingTest, LoadAndDeletePersistedPings); FRIEND_TEST(PingTest, PersistPing); - FRIEND_TEST(PingTest, DeletePersistedPing); FRIEND_TEST(PingTest, PersistPing_Load_Delete); - FRIEND_TEST(PingTest, SendPersistedPings); + FRIEND_TEST(PingTest, PersistAndSendPersistedPings); FRIEND_TEST(PingTest, DISABLED_SendUsingGoogleUpdate); + FRIEND_TEST(PersistedPingsTest, AddPingEvents); - typedef std::vector > PingsVector; - static const TCHAR* const kRegKeyPing; - static const time64 kPingExpiry100ns; + // pair>. + typedef + std::vector > > PingsVector; + static const TCHAR* const kRegKeyPersistedPings; + static const TCHAR* const kRegValuePersistedPingTime; + static const TCHAR* const kRegValuePersistedPingString; + static const time64 kPersistedPingExpiry100ns; + + void Initialize(bool is_machine, + const CString& session_id, + const CString& install_source, + const CString& request_id); // Sends pings using the installed GoogleUpdate, which runs in the // ping mode. the function waits for the pings to be sent if wait_timeout_ms @@ -192,11 +203,14 @@ class Ping { const CString& next_version) const; // Persistent Ping utility functions. - static CString GetPingRegPath(bool is_machine); - static HRESULT LoadPersistedPings(bool is_machine, PingsVector* pings); + static CString GetPersistedPingsRegPath(bool is_machine); + static HRESULT LoadPersistedPings(bool is_machine, + PingsVector* persisted_pings); static bool IsPingExpired(time64 persisted_time); - static HRESULT DeletePersistedPing(bool is_machine, time64 persisted_time); - static HRESULT PersistPing(bool is_machine, const CString& ping_string); + static HRESULT DeletePersistedPing(bool is_machine, + const CString& persisted_subkey_name); + void DeletePersistedPingOnSuccess(const HRESULT& hr); + CString GetPersistedPingRegPath(); // Sends a string to the server. static HRESULT SendString(bool is_machine, @@ -205,6 +219,11 @@ class Ping { bool is_machine_; + // The request id is the unique key that is sent out in Ping requests to the + // Omaha server. Persisted Pings are also stored in the registry under this + // unique key. + CString request_id_; + // Information about apps. struct AppData { AppData() : install_time_diff_sec(0), day_of_install(0) {} @@ -216,6 +235,7 @@ class Ping { CString installation_id; CString pv; CString experiment_labels; + Cohort cohort; int install_time_diff_sec; int day_of_install; }; @@ -227,6 +247,10 @@ class Ping { DISALLOW_COPY_AND_ASSIGN(Ping); }; +// Helper function that calls Ping::PersistPing() followed by Ping::Send(). +// Returns the HRESULT that Send() returns. +HRESULT SendReliablePing(Ping* ping, bool is_fire_and_forget); + } // namespace omaha #endif // OMAHA_COMMON_PING_H_ diff --git a/omaha/common/ping_test.cc b/omaha/common/ping_test.cc index 7f57fa5a6..18233d280 100644 --- a/omaha/common/ping_test.cc +++ b/omaha/common/ping_test.cc @@ -21,25 +21,53 @@ #include "omaha/base/string.h" #include "omaha/base/utils.h" #include "omaha/common/command_line.h" +#include "omaha/common/config_manager.h" #include "omaha/common/goopdate_utils.h" #include "omaha/common/ping.h" +#include "omaha/goopdate/app_unittest_base.h" #include "omaha/testing/unit_test.h" namespace omaha { class PingTest : public testing::Test { protected: - void SetUpRegistry() { - RegKey::DeleteKey(kRegistryHiveOverrideRoot); - OverrideRegistryHives(kRegistryHiveOverrideRoot); + virtual void SetUp() { + RegKey::DeleteKey(USER_REG_UPDATE _T("\\PersistedPings")); } - virtual void CleanUpRegistry() { - RestoreRegistryHives(); - RegKey::DeleteKey(kRegistryHiveOverrideRoot); + virtual void TearDown() { + RegKey::DeleteKey(USER_REG_UPDATE _T("\\PersistedPings")); } }; +class PersistedPingsTest : public AppTestBase { + protected: + PersistedPingsTest() + : AppTestBase(false, // is_machine + true), // use_strict_mock + app_(NULL) {} + + virtual void SetUp() { + AppTestBase::SetUp(); + + RegKey::DeleteKey(USER_REG_UPDATE _T("\\PersistedPings")); + + const TCHAR* const kAppId1 = _T("{DDE97E2B-A82C-4790-A630-FCA02F64E8BE}"); + EXPECT_SUCCEEDED( + app_bundle_->createApp(CComBSTR(kAppId1), &app_)); + ASSERT_TRUE(app_); + } + + const CString request_id() { + return app_bundle_->request_id_; + } + + App* app_; + + private: + DISALLOW_COPY_AND_ASSIGN(PersistedPingsTest); +}; + TEST_F(PingTest, BuildOmahaPing) { PingEventPtr ping_event1( new PingEvent(PingEvent::EVENT_INSTALL_COMPLETE, @@ -226,7 +254,8 @@ TEST_F(PingTest, SendInProcess) { } TEST_F(PingTest, IsPingExpired_PastTime) { - const time64 time = GetCurrent100NSTime() - (Ping::kPingExpiry100ns + 1); + const time64 time = GetCurrent100NSTime() - + (Ping::kPersistedPingExpiry100ns + 1); EXPECT_TRUE(Ping::IsPingExpired(time)); } @@ -241,81 +270,51 @@ TEST_F(PingTest, IsPingExpired_FutureTime) { } TEST_F(PingTest, LoadPersistedPings_NoPersistedPings) { - Ping::PingsVector pings; + Ping::PingsVector persisted_pings; EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), - Ping::LoadPersistedPings(false, &pings)); - EXPECT_EQ(0, pings.size()); -} - -TEST_F(PingTest, LoadPersistedPings) { - CString ping_reg_path(Ping::GetPingRegPath(false)); - - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(ping_reg_path, - _T("1"), - _T("Test Ping String 1"))); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(ping_reg_path, - _T("2"), - _T("Test Ping String 2"))); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(ping_reg_path, - _T("3"), - _T("Test Ping String 3"))); - - Ping::PingsVector pings; - EXPECT_HRESULT_SUCCEEDED(Ping::LoadPersistedPings(false, &pings)); - EXPECT_EQ(3, pings.size()); - - EXPECT_EQ(1, pings[0].first); - EXPECT_EQ(2, pings[1].first); - EXPECT_EQ(3, pings[2].first); - EXPECT_STREQ(_T("Test Ping String 1"), pings[0].second); - EXPECT_STREQ(_T("Test Ping String 2"), pings[1].second); - EXPECT_STREQ(_T("Test Ping String 3"), pings[2].second); - - EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteKey(ping_reg_path)); + Ping::LoadPersistedPings(false, &persisted_pings)); + EXPECT_EQ(0, persisted_pings.size()); } -TEST_F(PingTest, PersistPing) { - EXPECT_HRESULT_SUCCEEDED(Ping::PersistPing(false, _T("Test Ping String 1"))); - ::Sleep(15); - EXPECT_HRESULT_SUCCEEDED(Ping::PersistPing(false, _T("Test Ping String 2"))); - ::Sleep(15); - EXPECT_HRESULT_SUCCEEDED(Ping::PersistPing(false, _T("Test Ping String 3"))); - - Ping::PingsVector pings; - EXPECT_HRESULT_SUCCEEDED(Ping::LoadPersistedPings(false, &pings)); - EXPECT_EQ(3, pings.size()); - - EXPECT_FALSE(Ping::IsPingExpired(pings[0].first)); - EXPECT_FALSE(Ping::IsPingExpired(pings[1].first)); - EXPECT_FALSE(Ping::IsPingExpired(pings[2].first)); - EXPECT_STREQ(_T("Test Ping String 1"), pings[0].second); - EXPECT_STREQ(_T("Test Ping String 2"), pings[1].second); - EXPECT_STREQ(_T("Test Ping String 3"), pings[2].second); - - EXPECT_HRESULT_SUCCEEDED(RegKey::DeleteKey(Ping::GetPingRegPath(false))); -} +TEST_F(PingTest, LoadAndDeletePersistedPings) { + CString pings_reg_path(Ping::GetPersistedPingsRegPath(false)); + + for (size_t i = 0; i < 3; ++i) { + CString i_str(String_DigitToChar(i + 1)); + CString ping_reg_path(AppendRegKeyPath(pings_reg_path, + _T("Test Key ") + i_str)); + EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(ping_reg_path, + Ping::kRegValuePersistedPingTime, + i_str)); + EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue( + ping_reg_path, + Ping::kRegValuePersistedPingString, + _T("Test Ping ") + i_str)); + } -TEST_F(PingTest, DeletePersistedPing) { - CString ping_reg_path(Ping::GetPingRegPath(false)); + Ping::PingsVector persisted_pings; + EXPECT_HRESULT_SUCCEEDED(Ping::LoadPersistedPings(false, &persisted_pings)); + EXPECT_EQ(3, persisted_pings.size()); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(ping_reg_path, - _T("1"), - _T("Test Ping String 1"))); - EXPECT_HRESULT_SUCCEEDED(RegKey::SetValue(ping_reg_path, - _T("2"), - _T("Test Ping String 2"))); + for (size_t i = 0; i < persisted_pings.size(); ++i) { + CString i_str(String_DigitToChar(i + 1)); + EXPECT_EQ(i + 1, persisted_pings[i].second.first); + EXPECT_STREQ(_T("Test Ping ") + i_str, persisted_pings[i].second.second); - EXPECT_HRESULT_SUCCEEDED(Ping::DeletePersistedPing(false, 1)); - EXPECT_HRESULT_SUCCEEDED(Ping::DeletePersistedPing(false, 2)); + EXPECT_HRESULT_SUCCEEDED( + Ping::DeletePersistedPing(false, _T("Test Key ") + i_str)); + } - EXPECT_FALSE(RegKey::HasKey(ping_reg_path)); + RegKey pings_reg_key; + pings_reg_key.Open(pings_reg_path, KEY_READ); + EXPECT_EQ(0, pings_reg_key.GetSubkeyCount()); } -TEST_F(PingTest, SendPersistedPings) { +TEST_F(PingTest, PersistAndSendPersistedPings) { PingEventPtr ping_event( new PingEvent(PingEvent::EVENT_INSTALL_COMPLETE, PingEvent::EVENT_RESULT_SUCCESS, - 0, + S_OK, 0)); CommandLineExtraArgs command_line_extra_args; @@ -330,13 +329,34 @@ TEST_F(PingTest, SendPersistedPings) { install_ping.LoadAppDataFromExtraArgs(command_line_extra_args); install_ping.BuildOmahaPing(_T("1.0.0.0"), _T("2.0.0.0"), ping_event); - CString request_string; - EXPECT_HRESULT_SUCCEEDED(install_ping.BuildRequestString(&request_string)); - EXPECT_HRESULT_SUCCEEDED(Ping::PersistPing(false, request_string)); + time64 past(GetCurrent100NSTime()); + EXPECT_HRESULT_SUCCEEDED(install_ping.PersistPing()); + + CString reg_path(Ping::GetPersistedPingsRegPath(false)); + CString ping_subkey_path(AppendRegKeyPath(reg_path, + install_ping.request_id_)); + EXPECT_TRUE(RegKey::HasKey(ping_subkey_path)); + + CString persisted_time_string; + EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(ping_subkey_path, + Ping::kRegValuePersistedPingTime, + &persisted_time_string)); + time64 persisted_time = _tcstoui64(persisted_time_string, NULL, 10); + EXPECT_LE(past, persisted_time); + EXPECT_GE(GetCurrent100NSTime(), persisted_time); + + CString persisted_ping; + EXPECT_HRESULT_SUCCEEDED(RegKey::GetValue(ping_subkey_path, + Ping::kRegValuePersistedPingString, + &persisted_ping)); + EXPECT_NE(-1, persisted_ping.Find(_T("sessionid=\"unittest\""))); + EXPECT_NE(-1, persisted_ping.Find(_T(""))); // NOLINT EXPECT_HRESULT_SUCCEEDED(Ping::SendPersistedPings(false)); - EXPECT_FALSE(RegKey::HasKey(Ping::GetPingRegPath(false))); + RegKey pings_reg_key; + pings_reg_key.Open(reg_path, KEY_READ); + EXPECT_EQ(0, pings_reg_key.GetSubkeyCount()); } // The tests below rely on the out-of-process mechanism to send install pings. @@ -392,6 +412,7 @@ TEST_F(PingTest, DISABLED_Send) { install_ping.LoadAppDataFromExtraArgs(command_line_extra_args); install_ping.BuildOmahaPing(_T("1.0.0.0"), _T("2.0.0.0"), ping_event); + EXPECT_HRESULT_SUCCEEDED(install_ping.PersistPing()); EXPECT_HRESULT_SUCCEEDED(install_ping.Send(false)); } @@ -414,8 +435,61 @@ TEST_F(PingTest, DISABLED_SendFireAndForget) { install_ping.LoadAppDataFromExtraArgs(command_line_extra_args); install_ping.BuildOmahaPing(_T("1.0.0.0"), _T("2.0.0.0"), ping_event); + EXPECT_HRESULT_SUCCEEDED(install_ping.PersistPing()); EXPECT_HRESULT_SUCCEEDED(install_ping.Send(true)); } +TEST_F(PersistedPingsTest, AddPingEvents) { + time64 past(GetCurrent100NSTime()); + EXPECT_SUCCEEDED(app_->put_isEulaAccepted(VARIANT_TRUE)); + + struct PE { + const PingEvent::Types event_type_; + const PingEvent::Results event_result_; + const int error_code_; + const int extra_code1_; + } pe[] = { + {PingEvent::EVENT_INSTALL_DOWNLOAD_START, PingEvent::EVENT_RESULT_SUCCESS, + S_OK, 0}, + {PingEvent::EVENT_INSTALL_INSTALLER_START, PingEvent::EVENT_RESULT_SUCCESS, + S_OK, 0}, + {PingEvent::EVENT_INSTALL_COMPLETE, PingEvent::EVENT_RESULT_ERROR, + E_FAIL, 0}, + }; + + for (size_t i = 0; i < arraysize(pe); ++i) { + PingEventPtr ping_event(new PingEvent(pe[i].event_type_, + pe[i].event_result_, + pe[i].error_code_, + pe[i].extra_code1_)); + app_->AddPingEvent(ping_event); + } + + Ping::PingsVector persisted_pings; + EXPECT_HRESULT_SUCCEEDED(Ping::LoadPersistedPings(false, &persisted_pings)); + EXPECT_EQ(1, persisted_pings.size()); + + for (size_t i = 0; i < persisted_pings.size(); ++i) { + time64 persisted_time = persisted_pings[i].second.first; + EXPECT_LE(past, persisted_time); + EXPECT_GE(GetCurrent100NSTime(), persisted_time); + + const CString persisted_ping(persisted_pings[i].second.second); + CString expected_requestid_substring; + expected_requestid_substring.Format(_T("requestid=\"%s\""), request_id()); + EXPECT_NE(-1, persisted_ping.Find(expected_requestid_substring)); + + for (size_t j = 0; j < arraysize(pe); ++j) { + CString expected_ping_event_substring; + expected_ping_event_substring.Format( + _T(""), + pe[j].event_type_, pe[j].event_result_, + pe[j].error_code_, pe[j].extra_code1_); + EXPECT_NE(-1, persisted_ping.Find(expected_ping_event_substring)); + } + } +} + } // namespace omaha diff --git a/omaha/common/protocol_definition.h b/omaha/common/protocol_definition.h index eb97b7eaa..29389fdae 100644 --- a/omaha/common/protocol_definition.h +++ b/omaha/common/protocol_definition.h @@ -217,6 +217,7 @@ const TCHAR* const kStatusInvalidArgs = _T("error-invalidargs"); // Defines an Omaha protocol update response. The structure of the response is: // // Response | --- DayStart +// | --- SystemRequirements // | -<- App | --- UpdateCheck | --- Urls // | --- InstallManifest | --- Packages // | --- Actions @@ -285,9 +286,16 @@ struct DayStart { int elapsed_days; // Number of days elapsed since a chosen datum. }; +struct SystemRequirements { + CString platform; // "win". + CString arch; // "x86", "x64", or "unknown". + CString min_os_version; // major.minor. +}; + struct Response { CString protocol; DayStart day_start; + SystemRequirements sys_req; std::vector apps; }; diff --git a/omaha/common/update_request.cc b/omaha/common/update_request.cc index 1d0a54c00..278a3d132 100644 --- a/omaha/common/update_request.cc +++ b/omaha/common/update_request.cc @@ -42,7 +42,8 @@ UpdateRequest::~UpdateRequest() { UpdateRequest* UpdateRequest::Create(bool is_machine, const CString& session_id, const CString& install_source, - const CString& origin_url) { + const CString& origin_url, + const CString& request_id) { const ConfigManager* cm = ConfigManager::Instance(); scoped_ptr update_request(new UpdateRequest); @@ -60,11 +61,8 @@ UpdateRequest* UpdateRequest::Create(bool is_machine, request.origin_url = origin_url; request.test_source = cm->GetTestSource(); - GUID req_id = GUID_NULL; - VERIFY1(SUCCEEDED(::CoCreateGuid(&req_id))); - request.request_id = GuidToString(req_id); - request.session_id = session_id; + request.request_id = request_id; bool is_period_overridden = false; const int check_period_sec = cm->GetLastCheckPeriodSec(&is_period_overridden); @@ -113,6 +111,15 @@ UpdateRequest* UpdateRequest::Create(bool is_machine, return update_request.release(); } +UpdateRequest* UpdateRequest::Create(bool is_machine, + const CString& session_id, + const CString& install_source, + const CString& origin_url) { + CString request_id; + VERIFY1(SUCCEEDED(GetGuid(&request_id))); + return Create(is_machine, session_id, install_source, origin_url, request_id); +} + void UpdateRequest::AddApp(const request::App& app) { request_.apps.push_back(app); } diff --git a/omaha/common/update_request.h b/omaha/common/update_request.h index b7563bf26..8098b91dc 100644 --- a/omaha/common/update_request.h +++ b/omaha/common/update_request.h @@ -32,6 +32,11 @@ class UpdateRequest { ~UpdateRequest(); // Creates an instance of the class. Caller takes ownership. + static UpdateRequest* Create(bool is_machine, + const CString& session_id, + const CString& install_source, + const CString& origin_url, + const CString& request_id); static UpdateRequest* Create(bool is_machine, const CString& session_id, const CString& install_source, diff --git a/omaha/common/web_services_client.cc b/omaha/common/web_services_client.cc index 33d0696cf..5284293ff 100644 --- a/omaha/common/web_services_client.cc +++ b/omaha/common/web_services_client.cc @@ -40,7 +40,7 @@ WebServicesClient::WebServicesClient(bool is_machine) use_cup_(false), http_xdaystart_header_value_(-1), http_xdaynum_header_value_(-1), - http_xretryafter_header_value_(-1) { + retry_after_sec_(-1) { } WebServicesClient::~WebServicesClient() { @@ -59,7 +59,7 @@ HRESULT WebServicesClient::Initialize(const CString& url, static_cast(new LLock)); __mutexScope(lock_); - url_ = url; + original_url_ = url; headers_ = headers; use_cup_ = use_cup; @@ -146,8 +146,10 @@ HRESULT WebServicesClient::SendStringWithFallback( CORE_LOG(L3, (_T("[sending web services request as UTF-8][%S]"), utf8_request_string)); - HRESULT hr = SendStringInternal(url_, utf8_request_string, update_response); - if (IsHttpsUrl(url_)) { + HRESULT hr = SendStringInternal(original_url_, + utf8_request_string, + update_response); + if (IsHttpsUrl(original_url_)) { used_ssl_ = true; ssl_result_ = hr; } @@ -157,11 +159,16 @@ HRESULT WebServicesClient::SendStringWithFallback( if (SUCCEEDED(hr)) { return hr; } + + if (retry_after_sec_ > 0) { + CORE_LOG(L3, (_T("[retry after was received, don't fallback to http]"))); + return hr; + } if (hr == GOOPDATE_E_CANCELLED) { CORE_LOG(L3, (_T("[the request was canceled, don't fallback to http]"))); return hr; } - if (IsHttpUrl(url_)) { + if (IsHttpUrl(original_url_)) { CORE_LOG(L3, (_T("[http request already failed, don't fallback to http]"))); return hr; } @@ -171,7 +178,7 @@ HRESULT WebServicesClient::SendStringWithFallback( } CORE_LOG(L3, (_T("[fallback to the http url]"))); - HRESULT hr_fallback = SendStringInternal(MakeHttpUrl(url_), + HRESULT hr_fallback = SendStringInternal(MakeHttpUrl(original_url_), utf8_request_string, update_response); if (SUCCEEDED(hr_fallback)) { @@ -184,10 +191,10 @@ HRESULT WebServicesClient::SendStringWithFallback( } HRESULT WebServicesClient::SendStringInternal( - const CString& url, + const CString& actual_url, const CStringA& utf8_request_string, xml::UpdateResponse* update_response) { - CORE_LOG(L3, (_T("[url is %s]"), url)); + CORE_LOG(L3, (_T("[actual_url is %s]"), actual_url)); // Each attempt to send a request is using its own network client. HRESULT hr = CreateRequest(); @@ -196,7 +203,7 @@ HRESULT WebServicesClient::SendStringInternal( } std::vector response_buffer; - hr = network_request_->PostUtf8String(url, + hr = network_request_->PostUtf8String(actual_url, utf8_request_string, &response_buffer); CORE_LOG(L3, (_T("[the request returned 0x%x]"), hr)); @@ -208,8 +215,10 @@ HRESULT WebServicesClient::SendStringInternal( // The value of the X-Retry-After header is only trusted when the response is // over https. - if (IsHttpsUrl(url_)) { - http_xretryafter_header_value_ = FindHttpHeaderValueInt(kHeaderXRetryAfter); + if (IsHttpsUrl(actual_url)) { + retry_after_sec_ = + std::min(FindHttpHeaderValueInt(kHeaderXRetryAfter), kSecondsPerDay); + CORE_LOG(L3, (_T("[retry_after_sec_][%d]"), retry_after_sec_)); } if (FAILED(hr)) { @@ -316,9 +325,9 @@ int WebServicesClient::http_xdaynum_header_value() const { return http_xdaynum_header_value_; } -int WebServicesClient::http_xretryafter_header_value() const { +int WebServicesClient::retry_after_sec() const { __mutexScope(lock_); - return http_xretryafter_header_value_; + return retry_after_sec_; } // static diff --git a/omaha/common/web_services_client.h b/omaha/common/web_services_client.h index 2f1bd0a57..60155faed 100644 --- a/omaha/common/web_services_client.h +++ b/omaha/common/web_services_client.h @@ -81,13 +81,14 @@ class WebServicesClientInterface { virtual int http_xdaynum_header_value() const = 0; // Returns the last valid value of the optional X-Retry-After header or -1 if - // the header was not present in the request. + // the header was not present in the request. Only HTTPS X-Retry-After header + // header values are respected. Also, the header value is clamped to 24 hours. // The server uses the optional X-Retry-After header to indicate that the // current request should not be attempted again. Any response received along // with the X-Retry-After header should be interpreted as it would have been // without the X-Retry-After header. The value of the header is the number of // seconds to wait before trying to connect to the server again. - virtual int http_xretryafter_header_value() const = 0; + virtual int retry_after_sec() const = 0; }; // Defines a class to send and receive protocol requests, with a fall back @@ -125,7 +126,7 @@ class WebServicesClient : public WebServicesClientInterface { virtual int http_xdaynum_header_value() const; - virtual int http_xretryafter_header_value() const; + virtual int retry_after_sec() const; private: HRESULT CreateRequest(); @@ -165,7 +166,7 @@ class WebServicesClient : public WebServicesClientInterface { // testing purposes. Since the class allow falling back on an HTTP url in // certain cases, the actual request can go to a different url than what // this member contains. - CString url_; + CString original_url_; // True if an HTTPS request has been made. bool used_ssl_; @@ -188,11 +189,10 @@ class WebServicesClient : public WebServicesClientInterface { int http_xdaystart_header_value_; int http_xdaynum_header_value_; - // This member stores the value of the optional X-Retry-After header. If the - // server sends a positive value in seconds for this header, the request will - // return from the WebServicesClient::Send() call immediately. - // The default value is -1 when the header is not found. - int http_xretryafter_header_value_; + // Stores the last valid value of the optional X-Retry-After header or -1 if + // the header was not present in the request. Only HTTPS X-Retry-After header + // header values are respected. Also, the header value is clamped to 24 hours. + int retry_after_sec_; // Set by the client of this class, may be used by the network request if // proxy authentication is required later on. diff --git a/omaha/common/xml_const.cc b/omaha/common/xml_const.cc index e7994b087..bd233d3f0 100644 --- a/omaha/common/xml_const.cc +++ b/omaha/common/xml_const.cc @@ -45,6 +45,7 @@ const TCHAR* const kPackages = _T("packages"); const TCHAR* const kPing = _T("ping"); const TCHAR* const kRequest = _T("request"); const TCHAR* const kResponse = _T("response"); +const TCHAR* const kSystemRequirements = _T("systemrequirements"); const TCHAR* const kUpdateCheck = _T("updatecheck"); const TCHAR* const kUrl = _T("url"); const TCHAR* const kUrls = _T("urls"); @@ -100,6 +101,7 @@ const TCHAR* const kInstallTime = _T("install_time_ms"); const TCHAR* const kIsBundled = _T("is_bundled"); const TCHAR* const kIsMachine = _T("ismachine"); const TCHAR* const kLang = _T("lang"); +const TCHAR* const kMinOSVersion = _T("min_os_version"); const TCHAR* const kName = _T("name"); const TCHAR* const kNextVersion = _T("nextversion"); const TCHAR* const kOriginURL = _T("originurl"); diff --git a/omaha/common/xml_const.h b/omaha/common/xml_const.h index 3336fb1c8..a30439d29 100644 --- a/omaha/common/xml_const.h +++ b/omaha/common/xml_const.h @@ -45,6 +45,7 @@ extern const TCHAR* const kPackages; extern const TCHAR* const kPing; extern const TCHAR* const kRequest; extern const TCHAR* const kResponse; +extern const TCHAR* const kSystemRequirements; extern const TCHAR* const kUpdateCheck; extern const TCHAR* const kUrl; extern const TCHAR* const kUrls; @@ -100,6 +101,7 @@ extern const TCHAR* const kInstallTime; extern const TCHAR* const kIsBundled; extern const TCHAR* const kIsMachine; extern const TCHAR* const kLang; +extern const TCHAR* const kMinOSVersion; extern const TCHAR* const kName; extern const TCHAR* const kNextVersion; extern const TCHAR* const kOriginURL; diff --git a/omaha/common/xml_parser.cc b/omaha/common/xml_parser.cc index 107a792d1..4588eb2ac 100644 --- a/omaha/common/xml_parser.cc +++ b/omaha/common/xml_parser.cc @@ -581,6 +581,37 @@ class DayStartElementHandler : public ElementHandler { } }; +// Parses 'systemrequirements'. +class SystemRequirementsElementHandler : public ElementHandler { + public: + static ElementHandler* Create() { + return new SystemRequirementsElementHandler; + } + + private: + virtual HRESULT Parse(IXMLDOMNode* node, response::Response* response) { + response::SystemRequirements& sys_req = response->sys_req; + + HRESULT hr = ReadStringAttribute(node, + xml::attribute::kPlatform, + &sys_req.platform); + if (FAILED(hr)) { + return hr; + } + + hr = ReadStringAttribute(node, + xml::attribute::kArch, + &sys_req.arch); + if (FAILED(hr)) { + return hr; + } + + return ReadStringAttribute(node, + xml::attribute::kMinOSVersion, + &sys_req.min_os_version); + } +}; + namespace v2 { namespace element { @@ -743,6 +774,8 @@ void XmlParser::InitializeElementHandlers() { {xml::element::kApp, &AppElementHandler::Create}, {xml::element::kData, &DataElementHandler::Create}, {xml::element::kDayStart, &DayStartElementHandler::Create}, + {xml::element::kSystemRequirements, + &SystemRequirementsElementHandler::Create}, {xml::element::kEvent, &EventElementHandler::Create}, {xml::element::kManifest, &ManifestElementHandler::Create}, {xml::element::kPackage, &PackageElementHandler::Create}, diff --git a/omaha/common/xml_parser_unittest.cc b/omaha/common/xml_parser_unittest.cc index 88da91bc6..60349be30 100644 --- a/omaha/common/xml_parser_unittest.cc +++ b/omaha/common/xml_parser_unittest.cc @@ -46,6 +46,10 @@ class XmlParserTest : public ::testing::TestWithParam { return GetParam(); } + virtual void SetUp() { + RegKey::DeleteKey(kRegKeyGoopdateGroupPolicy); + } + // Allows test fixtures access to implementation details of UpdateRequest. request::Request& get_xml_request(UpdateRequest* update_request) { return update_request->request_; @@ -233,7 +237,7 @@ TEST_F(XmlParserTest, Parse) { // Array of two request strings that are almost same except the second one // contains some unsupported elements that we expect to be ignored. CStringA buffer_strings[] = { - "{\n \"distribution\": {\n \"verbose_logging\": true\n }\n}\n", // NOLINT + "{\n \"distribution\": {\n \"verbose_logging\": true\n }\n}\n", // NOLINT "{\n \"distribution\": {\n \"verbose_logging\": true\n }\n}\nSome strings inside an unsupported element, should be ignored.", // NOLINT }; @@ -310,6 +314,11 @@ TEST_F(XmlParserTest, Parse) { EXPECT_EQ(S_OK, update_response_utils::ValidateUntrustedData(app.data)); + + EXPECT_STREQ(i == 0 ? _T("win") : _T(""), xml_response.sys_req.platform); + EXPECT_STREQ(i == 0 ? _T("x86") : _T(""), xml_response.sys_req.arch); + EXPECT_STREQ(i == 0 ? _T("6.0") : _T(""), + xml_response.sys_req.min_os_version); } } diff --git a/omaha/goopdate/app.cc b/omaha/goopdate/app.cc index 3a13281bf..dafbbd7ba 100644 --- a/omaha/goopdate/app.cc +++ b/omaha/goopdate/app.cc @@ -943,7 +943,10 @@ void App::LogTextAppendFormat(const TCHAR* format, ...) { void App::AddPingEvent(const PingEventPtr& ping_event) { __mutexScope(model()->lock()); ping_events_.push_back(ping_event); + CORE_LOG(L3, (_T("[ping event added][%s]"), ping_event->ToString())); + + VERIFY1(SUCCEEDED(app_bundle()->BuildAndPersistPing())); } HRESULT App::CheckGroupPolicy() const { diff --git a/omaha/goopdate/app.h b/omaha/goopdate/app.h index 1cf10a9cc..c60bb7278 100644 --- a/omaha/goopdate/app.h +++ b/omaha/goopdate/app.h @@ -30,6 +30,7 @@ #include "goopdate/omaha3_idl.h" #include "omaha/base/browser_utils.h" #include "omaha/base/constants.h" +#include "omaha/common/app_registry_utils.h" #include "omaha/common/const_goopdate.h" #include "omaha/common/ping_event.h" #include "omaha/common/protocol_definition.h" @@ -56,12 +57,6 @@ struct ErrorContext { // Add more extra codes here as needed. }; -struct Cohort { - CString cohort; // Opaque string. - CString hint; // Server may use to move the app to a new cohort. - CString name; // Human-readable interpretation of the cohort. -}; - class DownloadManagerInterface; class InstallManagerInterface; diff --git a/omaha/goopdate/app_bundle.cc b/omaha/goopdate/app_bundle.cc index 62f5a4c5d..39d9acfc1 100644 --- a/omaha/goopdate/app_bundle.cc +++ b/omaha/goopdate/app_bundle.cc @@ -55,6 +55,8 @@ AppBundle::AppBundle(bool is_machine, Model* model) display_language_(lang::GetDefaultLanguage(is_machine)) { CORE_LOG(L3, (_T("[AppBundle::AppBundle][0x%p]"), this)); app_bundle_state_.reset(new fsm::AppBundleStateInit); + + VERIFY1(SUCCEEDED(GetGuid(&request_id_))); } AppBundle::~AppBundle() { @@ -193,6 +195,37 @@ CString AppBundle::FetchAndResetLogText() { return event_log_text; } +void AppBundle::BuildPing(Ping** my_ping) { + CORE_LOG(L3, (_T("[AppBundle::BuildPing]"))); + ASSERT1(model()->IsLockedByCaller()); + ASSERT1(my_ping); + + scoped_ptr ping( + new Ping(is_machine_, session_id_, install_source_, request_id_)); + + for (size_t i = 0; i != apps_.size(); ++i) { + if (apps_[i]->is_eula_accepted()) { + ping->BuildRequest(apps_[i], false); + } + } + + for (size_t i = 0; i != uninstalled_apps_.size(); ++i) { + if (uninstalled_apps_[i]->is_eula_accepted()) { + ping->BuildRequest(uninstalled_apps_[i], false); + } + } + + *my_ping = ping.release(); +} + +HRESULT AppBundle::BuildAndPersistPing() { + CORE_LOG(L3, (_T("[AppBundle::BuildAndPersistPing]"))); + + scoped_ptr ping; + BuildPing(address(ping)); + return ping->PersistPing(); +} + HRESULT AppBundle::SendPingEventsAsync() { CORE_LOG(L3, (_T("[AppBundle::SendPingEventsAsync]"))); @@ -203,20 +236,10 @@ HRESULT AppBundle::SendPingEventsAsync() { return S_OK; } - scoped_ptr ping(new Ping(is_machine_, session_id_, install_source_)); + scoped_ptr ping; __mutexBlock(model()->lock()) { - for (size_t i = 0; i != apps_.size(); ++i) { - if (apps_[i]->is_eula_accepted()) { - ping->BuildRequest(apps_[i], false); - } - } - - for (size_t i = 0; i != uninstalled_apps_.size(); ++i) { - if (uninstalled_apps_[i]->is_eula_accepted()) { - ping->BuildRequest(uninstalled_apps_[i], false); - } - } + BuildPing(address(ping)); } CORE_LOG(L3, (_T("[AppBundle::SendPingEventsAsync][sending ping events]") diff --git a/omaha/goopdate/app_bundle.h b/omaha/goopdate/app_bundle.h index ad728fede..c85e0a024 100644 --- a/omaha/goopdate/app_bundle.h +++ b/omaha/goopdate/app_bundle.h @@ -177,11 +177,18 @@ class AppBundle // log buffer in each app. CString FetchAndResetLogText(); + // Builds a new Ping with all the Apps in the AppBundle and persists the Ping + // in the registry. + HRESULT BuildAndPersistPing(); + private: // Sets the state for unit testing. friend void SetAppBundleStateForUnitTest(AppBundle* app_bundle, fsm::AppBundleState* state); + // Builds a new Ping object with all the Apps in the AppBundle. + void BuildPing(Ping** ping); + // TODO(omaha): missing unit test. // Sends the ping if the applications in the bundle have accumulated // any ping events. @@ -220,6 +227,11 @@ class AppBundle // if they don't, we will randomly generate one. CString session_id_; + // The request id is unique for the Ping requests sent to the Omaha server for + // this AppBundle. Persisted Pings for this AppBundle are also stored in the + // registry under this unique key. + CString request_id_; + // The current non-blocking command object if any of them is executing. // The class only checks whether the pointer is NULL to determine if a // non-blocking call is pending. We use a pointer because it can be useful @@ -261,6 +273,7 @@ class AppBundle friend class fsm::AppBundleStateInit; friend class AppBundleTest; + friend class PersistedPingsTest; friend class WorkerTest; DISALLOW_COPY_AND_ASSIGN(AppBundle); diff --git a/omaha/goopdate/app_command_ping_delegate.cc b/omaha/goopdate/app_command_ping_delegate.cc index e5e81b150..d81071cd9 100644 --- a/omaha/goopdate/app_command_ping_delegate.cc +++ b/omaha/goopdate/app_command_ping_delegate.cc @@ -76,7 +76,7 @@ void AppCommandPingDelegate::SendPing(PingEvent::Types type, apps.push_back(app_guid_); ping.LoadAppDataFromRegistry(apps); ping.BuildAppsPing(ping_event); - ping.Send(true); // true == is_fire_and_forget + SendReliablePing(&ping, true); // true == is_fire_and_forget } } // namespace omaha diff --git a/omaha/goopdate/app_manager.cc b/omaha/goopdate/app_manager.cc index 8dbd6bc3a..50f66d813 100644 --- a/omaha/goopdate/app_manager.cc +++ b/omaha/goopdate/app_manager.cc @@ -738,7 +738,7 @@ HRESULT AppManager::ReadAppPersistentData(App* app) { client_state_key.GetValue(kRegValueAdditionalParams, &app->ap_); client_state_key.GetValue(kRegValueTTToken, &app->tt_token_); - VERIFY1(SUCCEEDED(ReadCohort(app_guid, &app->cohort_))); + ReadCohort(app_guid, &app->cohort_); CString iid; client_state_key.GetValue(kRegValueInstallationId, &iid); @@ -1346,13 +1346,9 @@ HRESULT AppManager::SetTTToken(const App& app) const { } } -CString AppManager::GetCohortKeyName(const GUID& app_guid) const { - const CString app_id_key_name(GetClientStateKeyName(app_guid)); - return AppendRegKeyPath(app_id_key_name, kRegSubkeyCohort); -} - HRESULT AppManager::DeleteCohortKey(const GUID& app_guid) const { - return RegKey::DeleteKey(GetCohortKeyName(app_guid)); + return app_registry_utils::DeleteCohortKey(is_machine_, + GuidToString(app_guid)); } HRESULT AppManager::ReadCohort(const GUID& app_guid, Cohort * cohort) const { @@ -1360,26 +1356,9 @@ HRESULT AppManager::ReadCohort(const GUID& app_guid, Cohort * cohort) const { ASSERT1(cohort); - RegKey cohort_key; - HRESULT hr = cohort_key.Open(GetCohortKeyName(app_guid), KEY_READ); - if (FAILED(hr)) { - return S_FALSE; - } - - hr = cohort_key.GetValue(NULL, &cohort->cohort); - if (FAILED(hr)) { - return hr; - } - - // Optional values. - cohort_key.GetValue(kRegValueCohortHint, &cohort->hint); - cohort_key.GetValue(kRegValueCohortName, &cohort->name); - - CORE_LOG(L3, (_T("[AppManager::ReadCohort][%s][%s][%s]"), - cohort->cohort, - cohort->hint, - cohort->name)); - return S_OK; + return app_registry_utils::ReadCohort(is_machine_, + GuidToString(app_guid), + cohort); } HRESULT AppManager::WriteCohort(const App& app) const { @@ -1387,27 +1366,9 @@ HRESULT AppManager::WriteCohort(const App& app) const { __mutexScope(registry_access_lock_); - if (app.cohort().cohort.IsEmpty()) { - return DeleteCohortKey(app.app_guid()); - } - - RegKey cohort_key; - HRESULT hr = cohort_key.Create(GetCohortKeyName(app.app_guid())); - if (FAILED(hr)) { - return hr; - } - - hr = cohort_key.SetValue(NULL, app.cohort().cohort); - if (FAILED(hr)) { - return hr; - } - - VERIFY1(SUCCEEDED(cohort_key.SetValue(kRegValueCohortHint, - app.cohort().hint))); - VERIFY1(SUCCEEDED(cohort_key.SetValue(kRegValueCohortName, - app.cohort().name))); - - return S_OK; + return app_registry_utils::WriteCohort(is_machine_, + app.app_guid_string(), + app.cohort()); } void AppManager::ClearOemInstalled(const AppIdVector& app_ids) { diff --git a/omaha/goopdate/app_state_checking_for_update.cc b/omaha/goopdate/app_state_checking_for_update.cc index 6c3c98a48..262de1453 100644 --- a/omaha/goopdate/app_state_checking_for_update.cc +++ b/omaha/goopdate/app_state_checking_for_update.cc @@ -17,6 +17,7 @@ #include "omaha/base/debug.h" #include "omaha/base/error.h" #include "omaha/base/logging.h" +#include "omaha/base/vistautil.h" #include "omaha/common/lang.h" #include "omaha/common/update_response.h" #include "omaha/goopdate/app_manager.h" @@ -43,6 +44,12 @@ xml::UpdateResponseResult GetUpdateResponseResult( const CString language = app->app_bundle()->display_language(); xml::UpdateResponseResult update_response_result = + update_response_utils::CheckSystemRequirements(update_response, language); + if (FAILED(update_response_result.first)) { + return update_response_result; + } + + update_response_result = update_response_utils::GetResult(update_response, app->app_guid_string(), app_name, @@ -91,6 +98,8 @@ void AppStateCheckingForUpdate::PostUpdateCheck( const CString language = app->app_bundle()->display_language(); if (FAILED(update_check_result)) { + PersistUpdateCheckValuesOnFailure(app); + // TODO(omaha3): There is no guarantee that this is a actually network // error. In Omaha 2, this was called much closer to the send. Making most // errors, such as processing errors, app errors helps, but it could still @@ -236,6 +245,36 @@ void AppStateCheckingForUpdate::HandleErrorResponse(App* app, Error(app, ErrorContext(code), message); } +// This function will be called when the update check fails. In this case, +// Omaha looks into the response headers for relevant values. |daynum| or +// |daystart|will be -1 if the corresponding header value is absent. Client +// should not persist if either value is -1. +void AppStateCheckingForUpdate::PersistUpdateCheckValuesOnFailure(App* app) { + ASSERT1(app); + + const int daynum = + app->app_bundle()->update_check_client()->http_xdaynum_header_value(); + const int daystart = + app->app_bundle()->update_check_client()->http_xdaystart_header_value(); + + if (daystart == -1 || daynum == -1) { + return; + } + + // Registry writes to HKLM need admin. + ASSERT1(!app->app_bundle()->is_machine() || vista_util::IsUserAdmin()); + ASSERT1(daystart >= 0); + ASSERT1(daynum >= kMinDaysSinceDatum); + ASSERT1(daynum <= kMaxDaysSinceDatum); + + CORE_LOG(LE, (_T("[PersistHeadersOnFailure][%d][%d]"), daynum, daystart)); + + AppManager& app_manager = *AppManager::Instance(); + app->set_day_of_last_response(daynum); + VERIFY1(SUCCEEDED(app_manager.PersistUpdateCheckSuccessfullySent( + *app, daynum, daystart))); +} + void AppStateCheckingForUpdate::PersistUpdateCheckSuccessfullySent( const App& app) { // For offline install, we didn't send actual pings to server and the response diff --git a/omaha/goopdate/app_state_checking_for_update.h b/omaha/goopdate/app_state_checking_for_update.h index 5563cd2fb..405a4612a 100644 --- a/omaha/goopdate/app_state_checking_for_update.h +++ b/omaha/goopdate/app_state_checking_for_update.h @@ -38,6 +38,7 @@ class AppStateCheckingForUpdate : public AppState { void HandleNoUpdate(App* app, HRESULT code, const CString& message); void HandleErrorResponse(App* app, HRESULT code, const CString& message); + void PersistUpdateCheckValuesOnFailure(App* app); void PersistUpdateCheckSuccessfullySent(const App& app); xml::UpdateResponse* update_response_; diff --git a/omaha/goopdate/app_unittest_base.h b/omaha/goopdate/app_unittest_base.h index 2ce55a546..9a4e53994 100644 --- a/omaha/goopdate/app_unittest_base.h +++ b/omaha/goopdate/app_unittest_base.h @@ -36,7 +36,6 @@ using ::testing::Return; namespace omaha { -// Overrides the registry. class AppTestBase : public testing::Test { protected: AppTestBase(bool is_machine, bool use_strict_mock) @@ -127,6 +126,7 @@ class AppTestBase : public testing::Test { DISALLOW_COPY_AND_ASSIGN(AppTestBase); }; +// Overrides the registry. class AppTestBaseWithRegistryOverride : public AppTestBase, public ::testing::WithParamInterface { diff --git a/omaha/goopdate/goopdate.cc b/omaha/goopdate/goopdate.cc index 21c100760..c0117efca 100644 --- a/omaha/goopdate/goopdate.cc +++ b/omaha/goopdate/goopdate.cc @@ -539,6 +539,8 @@ HRESULT GoopdateImpl::DoMain(HINSTANCE instance, CString module_path = app_util::GetModulePath(module_instance_); ASSERT1(!module_path.IsEmpty()); + metric_omaha_version = GetVersion(); + OPT_LOG(L1, (_T("[%s][version %s][%s][%s]"), module_path, GetVersionString(), kBuildType, kOfficialBuild)); @@ -635,6 +637,8 @@ HRESULT GoopdateImpl::InitializeGoopdateAndLoadResources() { is_machine_ = IsMachineProcess(); OPT_LOG(L1, (_T("[is machine: %d]"), is_machine_)); + metric_is_system_install.Set(is_machine_); + // After parsing the command line, reinstall the crash handler to match the // state of the process. VERIFY1(SUCCEEDED(InstallExceptionHandler())); diff --git a/omaha/goopdate/goopdate_metrics.cc b/omaha/goopdate/goopdate_metrics.cc index 7997f818f..1c30ae739 100644 --- a/omaha/goopdate/goopdate_metrics.cc +++ b/omaha/goopdate/goopdate_metrics.cc @@ -51,4 +51,7 @@ DEFINE_METRIC_count(goopdate_constructor); DEFINE_METRIC_count(goopdate_destructor); DEFINE_METRIC_count(goopdate_main); +DEFINE_METRIC_bool(is_system_install); +DEFINE_METRIC_integer(omaha_version); + } // namespace omaha diff --git a/omaha/goopdate/goopdate_metrics.h b/omaha/goopdate/goopdate_metrics.h index e57522e13..efa7f850f 100644 --- a/omaha/goopdate/goopdate_metrics.h +++ b/omaha/goopdate/goopdate_metrics.h @@ -76,6 +76,9 @@ DECLARE_METRIC_count(goopdate_constructor); DECLARE_METRIC_count(goopdate_destructor); DECLARE_METRIC_count(goopdate_main); +DECLARE_METRIC_bool(is_system_install); +DECLARE_METRIC_integer(omaha_version); + } // namespace omaha #endif // OMAHA_GOOPDATE_GOOPDATE_METRICS_H_ diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_am.rc b/omaha/goopdate/resources/goopdateres/generated_resources_am.rc index 8b534420829ace72fff37d291004ee5f3e307e08..342c07be2d50dd42448f56478c082792b1f61c8b 100644 GIT binary patch delta 313 zcmaE}i*dpp#tAx%W*c?qvQN%qSJ-@wy@^-+oR9*;QlY6rAA~rBCj;4Uh2(_R3TaMm zAWsyvf#$Q@yn*gRK$F_WSKLlMJEh5#VWWq8W)9>@Zbd0-ZZPTy>= z#Lh@q+2o5V>XUPnQ;1agjaZeN8&sOOWZw$$3MUGI{EExpdiviuCoeJ*+H7QLr2+s~ Chhy~s delta 192 zcmbQRhw;rW#tAx%CX+XYOKx;)VV|rKDYN+(dl9cVtB?YN0>e_FsX`xwID{tyd2&K) zg>)xB6c^q+O;mvsw*n2($#c}WCclw8!YI3Wqx@o~$%j9vro=pSJ-@oeV;h9B7?%@hhox`H^>_}X|SoYIkEY&DKNOQ zxdBOaHWxMzpokWbt;%4?pvaH{#0m`BKy_|xUTm5`aSb5P1I+hj(`1+|ps>S{Vq+#3 zDrim?P}CvXBz>SGy?_|vAP`TTO%22co7AFcW>2h}jDb2Wq2@r?>Ok*<&DqSPw95hj D9(FSC delta 203 zcmX@Mjd9Ob#tAx%CL48Uvrh_A+We1wh4^G2W0A?b-2fECWMW4Z7a-h2AW*3bXTL7{OD186` delta 82 zcmcb2hVjH{#tAx%CL47ZvQJJ))Y~k;p(n>L!D7y0#Nx%`z~TX<4JNy*DNgQFSDKuo jDK`0l+BzURX|jMu4zDVMA%h}A3J@zWxNqL5vDOv8bMiIyBqCKNXb_=t^FfVTTL8T>L?ZwI delta 53 zcmcb0mT})1#tAx%CL49ET3m!uRX&rvr(5x)&o4-%Kruu?}-4>T(eXp1U?A%h}A3J@zWWPn`(bk*dG PQi?!xI5w}*u(JgKio-Q+ delta 225 zcmcb0n(@_X#tAx%CL49>Og)WLn*^spo&BWJrJCnt0q19n1j&d8EV`3!6HC8H=t||L&@Y! zHF>a{pOnC48Fh}y3)D5V(bO=c0&P)XP-QS=Pz2hb2xR9nWCF!Xf%*f@MJL1bN@*Bj Um>;eoJ2}K$2&QK991S~L0MLatCjbBd diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_cs.rc b/omaha/goopdate/resources/goopdateres/generated_resources_cs.rc index 9131a5af437a094fc6df1aed7c110b7c7db3d1c4..20a218d6914a96df8530ecb8a4d38e9b3e88f327 100644 GIT binary patch delta 476 zcmdmYnDN08#tAx%W*c>9vNJkPZqyfMPGwM-oXKvu`2)Kbmv{j~5ko#h1w$o+0z)xF zDv(zOA}1#*h)&iMRGQo&bc3Lpb;23q0ocvitSd5=pV^TiYw~Gj!(e}g0)|9}Y@mf@ z3=bLd7~TRcEdcVe8A^ecmon&qp#nn`LlVPZpqfO6ETEcXusUAGM4%cgpbk|ALk2~L z6d+!}P&_$TO?`5dN}o0PQIhcFvsiNN32I{5-~X@`rGl&2o{On6W9?{57g* zE>KnDMv|GlUo{>@WyWNv%FRV;S0u%eJ%{AB$$?zLn+qJyNQk2a3()sKw=$G$j*aAI jnLH)i!g)MX&$>4|Q2- diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_da.rc b/omaha/goopdate/resources/goopdateres/generated_resources_da.rc index 89bdf5fcbc9e2ecf1ecdf7cac7c9cd53c67e32c1..92a6ce9b3b148adffafff6a65972c01d6dd36c1f 100644 GIT binary patch delta 336 zcmaENnDNgM#tAx%W*c>9vro=pSJ-@o-9Vc8B}36~1 zlr!Wp>2nxTQ;l+77xZPozjcunL0 delta 154 zcmex!gz?>B#tAx%CL48Uvri6+l-m4_T}gWKH6@YB37jmG4U|9d9%V>jP+-VoNM*=k zP@MdbQ+TqRI@@FsDXGa3Dq`FU4EYSX40<3qxlu)$IhCPka=p6x8cgO>6Jsp_no~3xB;ugTF*!}mh*y=tkUha%9HlF1j9BsV`$n_~?CI-o2Q diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_de.rc b/omaha/goopdate/resources/goopdateres/generated_resources_de.rc index 8fc7abc3ceff60c69b09f25c87e1c86a20c281a0..2ff71ab871a42b86c820bff4e78144e426ac4a10 100644 GIT binary patch delta 370 zcmZ2vyHkl*(YbQD{Q{Reuqo6oFSDVli@y)RABG{vWgi>7*Z!YatTki z5mDOwMd*~MqZ?2%gCPe<76BC{fi>g;SuPCu4CM@YK$(1oM1~XwJ)l?^SXD7YDMK<) zj{;CWlc8v`p@q0$2~Zvc6&U=0>VdM8MKw>ehlAu9QYJIX3s3fu<>SXtqZLk2%|fks zLTWafYNvBbgPdLj#2}}Y04+`jIx`PQrZVJB{%9>dSpUZU6uP delta 202 zcmZp=!no)%;{+W>la0DF*(ZynDsBG5evFGhoFRiDlc9tml_3X67f%*c5Z(Mr=#A*) zBicffpQtFPx-t|o8i!HS9)6d1yQyds8Tphz-MvjR|C-egBDGo4`8P zX>v_A(~+9&q!l(odzrT~?_}0z*bkK7%RJdkQ-yUukh^j6M`Pj1YczU@QMyr6b8?HO zgb^-N6&O?*3>g#|Qh->2VK>mm13>qj0a`P8gQkxmaoWx?A7tJL)Up-m1)znSEwns1 jBxf_PVcrBZ?+6epFzf*O=P=kmhbDhi7vH?csKFEfE`?iD delta 171 zcmdmSk#Wxj#tAx%CL48UvQIvhtTcHa7sqB64hx0J6U=2MhiDj0UZ9~gS;#5Uo_s)B0W9RCr6QurV921zkOIUC4Cj~+GH+!*1Xr+m zpOzPg=3?d}%sYXi3JhDB4**$*nYT0VVP3<$7s%QQl{w73k@?VMMNQ$&7RC*x0KQB% AhX4Qo diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_en-GB.rc b/omaha/goopdate/resources/goopdateres/generated_resources_en-GB.rc index b5e59574237711b57ca77bd6fac9a0ab9d0a41be..1189211ce1aa4f90b18de4fa7d774109128528f3 100644 GIT binary patch delta 144 zcmaF1hw;>2#tAx%W|J8sBsaQsu}>~xSD4%qDK>cyJICf<>@8Bl3JgUIsSLRci42(x id0?DAxmM{WR`Izi>XU1fy>QCCQ4YW*w>e3L#R>on?(ulzsd0DSVBOH`r^CK`xMwu;c2d@qb+vR0@Zr#nMF5T-NaY)%a|W|+>}O;q$4Qt>-lZxqnN3weKbRqv zA)TR=A&()2A)ld`L4lzNC{oN&!jK3QD*>~ufTF4lh75`fDU&}s2v2rU5u2Q&x`8ac rK5BNlz6_Z_vrB=d6KmrgRf)+L)C@E|fI5nRE+fvJKwX=i)PrmQ^AbZR delta 196 zcmex%oN>x=#tAx%CX*+|N^W$U!akWJUTL!c#~GQ)&#d((-%uBttfVR@ugYM^pvaH{ z#0m_>453s@gn9J<0|EeXB1p diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_es.rc b/omaha/goopdate/resources/goopdateres/generated_resources_es.rc index 23c622a35bf3b219ae5aa629ff4bb7c2bb123e2c..691482565fd5ed01c2f6554fa3fd78d3127bff6e 100644 GIT binary patch delta 253 zcmX?hiE-0q#tAx%W|JQ#Np5tT#6G!(U19SRb}j`|4TfTdREBhhQieQ+6oz~tPl2Hb zC{oN&!jK3QD*>~ufTF4lh75{8HHr+HlP{{NPd3q*XH16f$?r8n4K)~Y88U&UmjcZv d%FfC0n(?|C3>iSxML>5E;Yy%A+MBf8>;axtH$(sc delta 170 zcmdmVneo^q#tAyiCJYLb856`ex=muAd?ZC_Gattnd0ABkLk2~L6d+b$C}v1yNM|Tz z$OH2888jG*Cp&5hPxjE*LQs|VAC-*6HOcqel04cRoQNU^%NLihV6-dcG6&ajLfF^BbQVp^K0L{NYqW}N^ delta 161 zcmZ3npYh5*#tAx%CL49v&jd;B{#awVxOGHZm{_e`zC$?4K{T)L$>v7XMp4xHXen^d&DRV^Cnw2b!h8pbM070n+Mh zu54OtAf6kL=gOu7RHe_Rrl7!}%3#Q#$dCfW3Jls{`7>ECK79T5$jX delta 329 zcmeC#%eZb2;{+W>lgaWCk{jJ-u}@wTDYBV^V;4WaKASq58=DK82b(^d0)xrqSV`&0 z@5HC^p^9&wBB8^`jU+btp{VR6NtVs;B+s!=ZqS#SEGMC&tH5B)X32I2XpSqJ4$wS( zHa!LqRA5kLFl10`G9rKARKJRZf#9D!WSQ0&RBzx)9U+$sd%(fL>PsI-v~BVFrp~n_s9bu>=5h2t$AX diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_fi.rc b/omaha/goopdate/resources/goopdateres/generated_resources_fi.rc index 453fe69a23edc4ec807f3542b0e8d8d9de873cf8..91d3d26ac444f213381eeabbf442cca8431c99d8 100644 GIT binary patch delta 156 zcmaEHnDO6X#tAx%W|JGEB{#aYuusloSD4HaE3x?o#a{|kU4o<UO=>mP07%Ox AT>t<8 diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_fil.rc b/omaha/goopdate/resources/goopdateres/generated_resources_fil.rc index cd909f79913447bf5c91d6a61474aeab84466fcc..8090c96cc7f14eb3581cfbd13f89636833fab38c 100644 GIT binary patch delta 258 zcmdmSit*8D#tAx%W*c?8*(b-aD{MZ(t|BYx$B@X7%}~mq$e_UB!H~(2$B+Uf6&Ug+ z>#K=R)=~}71hRo@6c}=VWFA90kOiYb;w3=UAY8|{GrgUJ;dLX&k=112Y^s7*ej adSSAhn#SaJYC&Lnl6nM)-fW|>%oYFx?HarQ diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_fr.rc b/omaha/goopdate/resources/goopdateres/generated_resources_fr.rc index 44c95ef434a20364025805646e077a1f571b0759..3bc137b84e2036b6b320353ae6b5453d06bd7c27 100644 GIT binary patch delta 92 zcmZ2>f$`3H#tAx%W*c>9vQN%pSD5UQEH?R<8rSAe><03a%}n?v=SV9|j#Jl|JVV`P p@&_%o$$!*mf!Uwb6ehE28cg=kw3-ZJF9FgYG%Y~v&0bn}Yyo6;Bh&x@ delta 120 zcmca}o^ja)#tAx%CL48UvQOR=C$;$tyOaFnefAEMGt^ZkPtp>Z+^23exrkF}@&+}r y$?w!>O_tN(m^@312QL0WQ)2QP4Gp-sn5G3-JxIJv(+DoUO4AG^zWIaZ8(RRqq%1!G diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_gu.rc b/omaha/goopdate/resources/goopdateres/generated_resources_gu.rc index faf904617ec3847be905e87f503b0d76766bb6fd..d8540b176d0b762624eff42be4eb5e2e10dbcd51 100644 GIT binary patch delta 212 zcmX?emhr_o#tAx%W*c?qvrjHyS729QXyuy0wPdm*hw$c4>>+ZB3JgUIFBt-WIG5om w!+RhLMCO56AUb`rwx;^z9JL2TsBBbKoZO(nF}XxNi3HXEh*iD0LBq!m01h-o-T(jq delta 61 zcmaEHj`7S{#tAx%CL49*llM6IBCZADHg0iz9vQN%pSJ-@s{RbnbDW?IaFQ*x&#^#%xlexLIIqiW03JeyU z?vw4!q&N48RxqLqPVN&Gm~0{Lf~2=w{4h5wD^REVh*Gsek!9BiApO!%0PWjD*4iL*>j)8(7& MWG1ya%F00<0PxECHgArL^vY)sMhOXJ-hq?KMIW0LA7&L&S1JF>#$$`?slZB*3kTi>K zKBPQ@9WHQETYK^ZZ9N!&^GWSkHaN%7h>?krf3vZPFcVxX&`g{K#+h7bCcAlpm4i9} D{I@S~ diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_hr.rc b/omaha/goopdate/resources/goopdateres/generated_resources_hr.rc index 83777651262831fd9c52162ff7d242d0239ab7a5..f6b20d3b22c41b40a62639c4890e0dd5fedf7766 100644 GIT binary patch delta 96 zcmeA=&iLjS;{+W>vyHm**(VpUD@=AW6q(!*#kKhx`!{JuugUL~9VPP^@)^n)@)$B1 w6c`GC>}-ZohD63hhOEiDs```Tl*J}bQ0bYhrlga;MBsaRXu}?0G)7s3%@lBf9ks)g`ql%+&HbW^xB4Z*$34;Oy xJ7X$CE<^t0hnm7HRSby?le1I~O+KYAG1*8p2}~!ch)v$08UxRl9yq>1r#j;@)>P}*&YJr)D$N3s47kFP*a+$pdvOoLA8eoE@U;?PfZ5IEl{ff LQk&nY-Le4ywCy9X delta 134 zcmca}obkkQ#tAx%CX)+eB{#Ztuupywr!n~r7sqBHjx93Mjtp5qmQNN#lNVxL^Xt}rv;j#(P(^d{ zHDwzVk!%#6=H?|TD(u2OKtuBwvKUGkN*J=iY=y}e#Y86?$;(XU(J`2ONlavN6R*(b I1f6R}01P8GegFUf delta 183 zcmaE}k8#^R#tAx%CL47Zvrl#kliK``y+dlUn1zgX9z!}qDMKDZ3XsfT&|^?w@MTB^ z@{<|z8Il+hf&5a293Tx;H~FZN{Nw;twaFsN8zyg1(U|;A*#=Cfs5oujpyI=>?hVwM z3)YsykO|b94dg2@cmg#SGn4=g0U1=xkU9CIj__nYHLl4HItGH6vJ(x2H&4^KW&{9= CY%&G_ diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_is.rc b/omaha/goopdate/resources/goopdateres/generated_resources_is.rc index 488e4f19a6a6943e6381655977991953d0642789..ff5c0150784d6127c6df154407df1eea62b7b295 100644 GIT binary patch delta 184 zcmX?hka5Bx#tAx%W*c=EvQI8zSD1V+T4wSZEso9q*l$VO2QfTj$Yw}n$N|DkhCCot zWKdx61F}Cblrj`CWPs&BJOzdlhR;B?#XwqtAr;8VX2_f@sA9rMrtz`$0O;<0hS_@nN-9ktB49ro?yf>*+9i) l@)SXV$qg!7z;uAB7nGKmd`{JFa+{67vyHlQ*(c|*D@lgS?wBsaRXuuslNQrg7vNlrAFp@1QiA(0`OA(bJIp#;d*V^Em< sQLS-ufR@_iHR=Z@e^S?&yh6ioa+|uqQ0Eg2b_y7O^ diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_iw.rc b/omaha/goopdate/resources/goopdateres/generated_resources_iw.rc index ffb76dc6af46af942ac6d7239f37153e4a02b657..1af1dd80c48ea43070753046939cc8a72c994ccd 100644 GIT binary patch delta 140 zcmeyif$`2p#tAx%W|R4YBsaQEV4s}BZm{_idziS=J=W{2mswx3>M?+z0>cB=tE{hB nUjRu3hDSj1GV5e61&zry@)LxxO2uIlPE$z3BE0#O!Wwe`#cneX delta 57 zcmcb!k@4FG#tAx%CL48EvQPdKEVB6@dz?7WOV+Eb7g_ZfKyY%M{Eo>D@@kU{6wD^? MQb^fsq`1l)0E`M1T>t<8 diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_ja.rc b/omaha/goopdate/resources/goopdateres/generated_resources_ja.rc index bb973695e1583b5fd3c8f77b4e034beb9203c370..cb7d5c0c3b9d1635eabd9349ca0bfff93b65fad5 100644 GIT binary patch delta 65 zcmV-H0KWgIrUAyL0gx;KHnA=t8?*KY^b;6oFikLiFk3K_FlR7V XFkdhNFpW`WicE-;yc{;OE*$zc#tAx%CL49lG^->oke7_m56|(DuW?|B0~xgD==KD?1|4d=nYKk R^63bloGWLzIZ5V;831756QckC diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_kn.rc b/omaha/goopdate/resources/goopdateres/generated_resources_kn.rc index 1758d168823da41f842bccb25b5de30e9e21ce4a..1083de6e61d7cf5e50a41d3e38c3bfc52effb63b 100644 GIT binary patch delta 252 zcmex!o^i!R#tAx%W|Jo-N^W#(VV|7Gt}t07S!VJ)eU8n)*i9HkT6tFSoaNzBSjcmn zXFiz4qp;bEvp`N!fuV@uB|`uZ=Q2EHcn@TO$UHC$M5j;AS5u#SLHz*{D%Wdt6QxRX Wa*}2eaVj^z(fne9-T80g1ULbXrc?U> delta 108 zcmZ2+k@3%Y#tAx%CL49$Z&*m`B r0=daOYHE}DG#*SAl2Mp!pqT}wIVL~ROoFjDPtf{ef~s{!yZ|QvJrE^Z diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_ko.rc b/omaha/goopdate/resources/goopdateres/generated_resources_ko.rc index bc1b77f954c135d0f48c8f5197c30e944d8b3761..f65a6495a76e4758b2e94076fa48d26e791ae649 100644 GIT binary patch delta 128 zcmX@Ikn!C@#tAx%W*c>9vQN%pSJ-@s-AdT%!chf=Cx1j{yV~7*rVy859{(fSBW~0>g?8KF23FNU2TEkZxjwa_wX^CJV{vAh-!o K=H_`aY9;_~tuBKA delta 84 zcmaF2knzYu#tAx%CX@TUBsaP>uuo?5k=y)(T|;>C3Spti6%ss?ZKNe8$H}TqZjf%8 cTp+A4`HVEjWCIx;IJ-;60><9_LFS(^0Pn~hRCoY-|WEC-#FysSqF@pj_0Z>Kq#klA;;{+W>vyHk7*(VpVD@+#1(3)&u#Ic!&la0Cy*(Wc^Fq>Rp#Iad{rWJI+ K^yV`<*Bk)L1{bRU diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_mr.rc b/omaha/goopdate/resources/goopdateres/generated_resources_mr.rc index 78261070d020f2332ccf4cadf059b381f3656541..c08dca4c865e5be30b0e4a5ab2893997ebdf3fbe 100644 GIT binary patch delta 185 zcmex$nsM4$#tAx%W*c?qvQN%qSJ-@wy+%$^fuV@uB|`uZ=Q2EHcn@TO$UHC$M5k{K eRAXl(tZec_bPbYY>?TT;=H@9HX|@1lBsaRXuum?CmD>D+Jx^}3k*eC{b!rbLFH%*Qd_g@6N^?wZ O(MW=^HydcC*#ZEtMH;{W diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_ms.rc b/omaha/goopdate/resources/goopdateres/generated_resources_ms.rc index 7a7382a1a08cb2c208e910976dcf4b1640017c3e..1680aeeb13ea1d43d27cf356e6a4652f8289f8e9 100644 GIT binary patch delta 112 zcmbPpfbre|#tAx%W|P-PN^W$U#y&ZV-C*+%b}4CgUxrkMJci`S!per63Jf_6i45rs inUhzls!z^R-i0KR2o&*BaX}N=qT+=rvROs-hZO*OE+9Do delta 66 zcmcb2fN{9y=gGRthLhi@s!i@w-ZeQ$ UB@2i(Ccjhh0MVN>RKHmP05lL7R{#J2 diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_nl.rc b/omaha/goopdate/resources/goopdateres/generated_resources_nl.rc index d35775a0d7f629ac5c3942d3d30d7393e5c6643b..83b7b8ec9c2113e234063abe337f0897900e1461 100644 GIT binary patch delta 114 zcmdmVit*Jc#tAx%W*c>9vQN%pSJ-@seV-hwA45Jv`s7}<`*4==WC0C{$y?Mlw83%= u3Jj_Yh75`fDL|~ikjs$CkjGF8ge466a9+t|LjzHuJ}-zVo5MA3+W-KX&>pe? delta 88 zcmaELigD8^#tAx%CL48UvQMr_P}=;5eTCfQ3F-!u<21!4o2Us)W>Rkh@(Ywz84MW| m8B%~)fgzV6lOd0xltBZCH5p2PbSjXqIayyLdh;ZW8#Vy_=^1VS diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_no.rc b/omaha/goopdate/resources/goopdateres/generated_resources_no.rc index c2410779b0bb62a00808b36da6e52c9df4ef2245..69d863773091809655039e0911453170bf8f04c5 100644 GIT binary patch delta 194 zcmZ2+gz?@H#tAx%W*c=EvQI8zS76kgtjH<8`4hVzk8mPGDMJZEDnlNS%w#AAvWhnQ zi!9}5cVsAHNN32H{8u@cNljsLn2Hj+0#HRdL)PT;T%wcnl*J~`Q<;QKDnLzQa)YW8 wNNR;DsxFY!CsiF)H3bC*RR%)_MTQh0Rsh?b3$$AUXsITU54UG?fZ7df0BCSBj{pDw delta 149 zcmcb2gmJ|Y#tAx%CX?SsOKx=QV4s{8tFxJp!;MEYogtqgg&~_Eiy@UE4+t}XIDK*; zm+9vro=pSJ-@o{gX_l6N3{YD`N_S0z&~qK0^{iCPOMi5kn$F z9*~vDpa&EW0E*`U+2vr7T(HU_hR;B?l8kyl6)-hbKy}3oB|w!!Ky|7Nh75`f zDL}k{p?Gqky87fTssfXXR2!5*W)f0w2vo18rlw9e}*iER3KJlP?#L3Ex4Jch>%`3#Ccmj7f% zRbg2LhBSsmh8&=5K0_&k9#A}lAr+{q1SncG`Mjt&b1FmbLwg=`B=qG)ylDnZ{DaTZ36%-+8!AI delta 76 zcmbPnjPcA-#tAx%CL48EvQO5EQ`*eKaZ83(j{yiLe^fP|{6Jl7@)HSx$w8_;aM64y Pt5~fZ!rJ^-P1*(k$Ke-H diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_ro.rc b/omaha/goopdate/resources/goopdateres/generated_resources_ro.rc index 4acf80609c27363dada3462480b98cdd03d9f8cc..144b6f45689ceecda4ffd1dbc2a2b750c75b3d11 100644 GIT binary patch delta 786 zcmaJ|PUp-7R^Lk=E1c<|(#Z3GeNVfo&C-#72g%+A*> zdhnSx5;VJ!d}#y2rotE7%@YA(mdwCMdmmIv3K(MHbU=7O7RW6BR5DF0RD};=neB=( z3j0AT6YLHu1Oz6X97BZWDHWbLZXwliTr(*yv8PVc#^vYe>Ns@vP+GP^C~Spw#SI}j zhP*Coyo4!Ig_6qykL7W}C%~SpL&aNwigFeGY+Y$l@-LnLZ^F5#i z-tySab_0)0??m4LPhlgWpBCi7t2p_cZm4KGSZeBQoWhHU7w$&hVI9G9tzMnnBL$ShqD&bIPxB0@yaUhi&|Xfsud!|>r5#1m`#f16z)Z? H9MygUn|{t8 delta 729 zcmZ`$L2DCH5Pq-0y2KdQB<^n0HZ0Mm+jLXYxHOHaX%nOr2|b9E9wf013K1=#MChsJ zAVEqgfdLOiv?BB*MctcVS)qsMLGlYkBqtH+q2yE+-@I(07Z1DhzM1cvdGDL{SNfw# z8#*=MX`%1KZ2c^BieYHD1#k;9JtYcxp(>Z?6Y`jp*{6~caZ!~lkrFM#Magge79y1K zOrKlC2zl?Fw`=G4aqof(+n!~t+MYaT<-PZu(hDTpo;h<%-01BoQm_;S60(NryK)#q zOLYW{b&CMr#~8OBfK5z zxK2otAKS)n1fXV!P!E4%(9B(qQWw7Mi|U65H@(of@`}@jEa*&0&>j#$i)e5(EWvuD z<-`!EBNDtH))`*MoVlYN@rQ1XK1aDa`VfPIB)xJ9HB(WTifMf6YpD-vG4(vV0rQ%< zOqlb~%?j{6Ho$b|pV(gaj&BApff)C}!BvB+88*dukPp_!TWFI#Zs8~^@eR@DwU>yZ zhAyFZD)~!R*o^yRmHlz2jvc?cPAqUI7n33Ev6ifOi?qtL6;kbL zJIMvC%un*LJGuD3A%PTMb0&q}n9bBYZ)~S;!E$;V*JP(NE^L*V-p621?>bBSoE?Ee aHVVfxC);NkvydI*Z{Es{p?W_T3I7AGq1x;K diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_ru.rc b/omaha/goopdate/resources/goopdateres/generated_resources_ru.rc index 0d04526f27b5a176cf2dad4cef24b4bba24cf5d9..66645e108729dc56342321badc5fd8c96dd421c7 100644 GIT binary patch delta 229 zcmZ2>fU)NQ;{+W>vyHlQ*(c|*D@=BY7Tf%W{fQu>>E?@);+%?dEFLTtEQTyrECwtJ z431#h9VlW1cVOY3Jh{Ajx0_v+=)3u;q&VkfF&U}Jd*nDK-xJ~B zH)kUVhR*9Wig+utD-)+KuK)!6y+jbaiCfwu#5+b Z>Ew;dl4vTu389vro=pSJ-@o{hG9JFheS1B0~m4K0_HpB10ZSCPV6EM@ivu z1qOeH0-#7XLn%WRLn?y;Lotx202Ipyixo5IfuRCJ6i}p?p@iWf*n}*GUku4WQxq6@ zf#w!7SOHn842BGf3@JdoVDd*5;mHchVw3GusytzKBilf(spkGvGmRk^=>ELPjVhXx UC#i~gQ_tKCkeQo>)Gk;901%c_i2wiq delta 210 zcmdmRgz?c~#tAx%CL48Uvrle|;F}x}E3)|?`vGZb4~Be(0)}D+9R>v;S;COXkjRk1 zkjGHUP%`+szzdS Ig4zXZ00Ub!M*si- diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_sl.rc b/omaha/goopdate/resources/goopdateres/generated_resources_sl.rc index 8057c16fe8a024f92bc5575d17a333d2491bbdb4..4d69911cdfb7ff47a37a9cf6a9f9cc5c6217226f 100644 GIT binary patch delta 97 zcmZ2?jPc4b#tAx%W*c?)vrjH!H`vUI~L9IYxj*-A}h vvXZ#ay*L7nJ6h{6NiPGK-MVBvk>RFvsQq^?TL;+xi~* delta 108 zcmca|jB(vD#tAx%CX?^SNN#jn#y+_uPGoWp7sqB94hdOSFNS=EtjV^j#+rEynG6aH z1wei=LpDPxkW^sM149J{RR%)_MTQh0R$wTeyioP*4lx#XM;2=q0~W*0$~@DV;GDyJ z=S4W>SacW^7;ITgC(l>5)Ujf5X7K>3Gy-B97CRON274fB3&ci1tj7R?3Je@Twg=1P z11ciC&Ok{M7E=}t1`8I=$-Zjplb@&vOmXq9~y_d4dYZpt4T}ZPLT45ypoIoN3t_tBRMqqe>vjbC$_a=ej)m&od`$HT8?Pf! Q0_152kY_h<)hRUv09rXdVgLXD delta 214 zcmbPolyTJ&#tAx%CL49vvrk?StFc*vLyU#ffyIC&ip7G(XtOELbS4CMvMEpf<{E(3ItFUxPv4$HtVT9 WVdFLj+GoMy$l}CeuvuQW)D!@M>M(== diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_sv.rc b/omaha/goopdate/resources/goopdateres/generated_resources_sv.rc index 9ea811d0de10f52cbe291dd85ddedc9c2b172bf6..7ab8f0739ee92051f72e7d11e2ffbba1b649249d 100644 GIT binary patch delta 366 zcmaEIgz?r<#tAx%W|RL%OKx;)VV|7Gt}wYNR&4Vd_D9mHM;S606d3XtQW>%s6oD*1 zAS;C-hanM2rU1n=fjE6Kqp|YjJO!S~Iw}ITY6=Prstkre)hS>d#Xud|45dJIDGd4y z$h=gBBA|&+8A^aEihwdD3{NL3stHfNrY1JIOQj{)2Wm?qSRKd>DM0m$Bk9R3)-IeG3{Mzx8A=!uC#$L`s_QX; zpaO#`gCT<=LkbWpFcdSSGGsH9GUNgI8bEdtgXUywb@j<>R9Z|uV7h^#3Shm&=r)v8 zoGho#HhGOI-((GS5qVVmav3s#c9jC%1hWmM-bhUXq<(Uen%ZO|Nd=G@n-8c-*#H0$ CvNC`G diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_sw.rc b/omaha/goopdate/resources/goopdateres/generated_resources_sw.rc index 8658c8e715264bac07fddeaebb2d3e34ad8f412a..6853ededb9d7baadddea7949096d33a46f86b470 100644 GIT binary patch delta 226 zcmdmUj`7-g#tAx%W*c?qvQN%qS726P2%T)pCB69zyO+G80z(nQONIa-&SiMY@E*tl zk$GSih)&;ZtIp0ySlQ%@Qi_v5XtGVt(nuje^%qi9Z?4m9lV%NPNM*>L%JKJ=QrDP#L?a1I7ifa% d%`#do(wv?Qc?{_cnG98vm%4^;{^xo_5dhjG9?}2+ diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_ta.rc b/omaha/goopdate/resources/goopdateres/generated_resources_ta.rc index f46bd410bece8825b9a0992146b08a0ec5c8cfcc..957eda8d81ca5da51931aba69f7b8f28efe4446d 100644 GIT binary patch delta 189 zcmex#iLvhr;{+W>vyHkl*(YbQD{Q{ReosMBfuV@uB|`uZ=Q2EHcn@TO$UHC$M5k|F euffhpSlMJpZS~1_G*gIFnWjag%FQ3Nn(P3dn?DEu delta 64 zcmeCX!uaVD;{+W>la0DF*(YC15SeU{Dzu5?h{9we9kt0knhz#vC`{JV%7RcFlOJg% LL7AKTv>WUI5{ef9 diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_te.rc b/omaha/goopdate/resources/goopdateres/generated_resources_te.rc index fc0dc13212be06e20e108c6af516df374d7b2059..18f3a8c1cabdeb578f494c0c2b722adf56534625 100644 GIT binary patch delta 200 zcmexymT}5?#tAx%W*c>9vro=pSJ-@oeUY4^0z(nQONIa-&SiMY@E*tlk$GSih)$mz lt*JhFj@knvRBlvNoV-DUWAYO9Bob8XX%MM;^9BtMI{@z+L(u>L delta 60 zcmbPop7F<7#tAx%CX@9OB{#Y?u}@x>q_p`Tdym{?KUKBKPt*k_KT^9exj{o?@*nji OAl(IGZw}FPumb@2ml%xz diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_th.rc b/omaha/goopdate/resources/goopdateres/generated_resources_th.rc index 3b19711fdc890b6c3328dc8b8f2ed8b2d9c124a4..0f59644ffca96f0b2344a3f5fbc5de9b11132814 100644 GIT binary patch delta 105 zcmX@Li*ep=#tAx%W|QxSNp5tT!ag~J-C*-K_A*IMXFf?jT|QGj#>v@=PX!$KwE0x| b%z+|cF}}%uN=2B0`;;m$1UH)~i&+5x?-UpM delta 48 zcmV-00MGxPy8+6&0gx;KG_ftM2a~{96te;dei@UBA>@;iAt;j&ArOezfo Hb%G55+f6Fr delta 76 zcmdmSl=00G#tAx%CL49Dy9uudiyeyzivf!hkha?F$nj8`*PbN| zD5SvP4it8ryiiJfa)T<%WGfXl5pkf1HH!s{2M}8WH8`^PvrLXtIfF|=VRD0-*yK1> SE$j-~RCBOOZ2q8n%L)J%^(Q<4 delta 78 zcmX?di1E}x#tAx%CL49PvQO5C;F(+y!!enQ!-iL$#ev0+#TZB$u-Hsav=^RSqr|hh ifa8et?25x*9$J diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_ur.rc b/omaha/goopdate/resources/goopdateres/generated_resources_ur.rc index c15c6afbf46324d0a27d86713a0492b9bdaefe59..39d7537a19e2686074f49a0319790afe53ff3d28 100644 GIT binary patch delta 199 zcmexxh;iCs#tAx%W*c>9vQN%nSJ-@s-A|hH44XQe0)rl#{$zb+&B^=BIVL-a%CMgS zis`VaPp((i6i{H$0IG3f1Bo4EyTmqmo${{9^GrA<_bE&9qe)JlFQGVDN0npp9u*C! l8UayPHaE6Ppk@?fpen6kswCI5?E|Yjh(jgE=0mFMtO44FH{k#P delta 189 zcmbPsnDN6Q#tAx%CL48UvQM57V>H=Lmt(UChk`V}I-3XEK{f>jJvMzdb+$8;ZIv}S z6&TjDodNQ$OkQXyJ-J0yY4QeTE>;Z&BR0*+6P45_e^8z>IYEtM@;@cE$$cskY+xCN z$p=(5Cf`%hfJ+IeiU6gI*)$DAontc}#{((GkjW1@g(n}AP-0bJ5MWH4TrVcd es>c9?lkJtSPIgjOne3qAF?oVY*=9b~7;6Bn)faC7 diff --git a/omaha/goopdate/resources/goopdateres/generated_resources_zh-CN.rc b/omaha/goopdate/resources/goopdateres/generated_resources_zh-CN.rc index 07465c0b26360d7d25ddf3912024bad373c873cd..31b89dc0e11736f071b1e86786a6e851e81b94aa 100644 GIT binary patch delta 177 zcmZpg!Z>LP;{+W>vyHl&*(bNKD{Owl-o~$xoUIXlcH-4;H3gpkH~JZ-D=?@s7&0g_ zqyVu3!==i}Z^YCl?-EZE!y&y+Kwla0EY*(XnP;G1mY%Cnh|qk>=Qcg_8}laomnwVWyQiLx= + OSVersionFromString(min_os_version)); +} + +} // namespace + // TODO(omaha): unit test the functions below. // Returns a pointer to the app object corresponding to the appid in the @@ -343,6 +377,26 @@ HRESULT ApplyExperimentLabelDeltas(bool is_machine, return S_OK; } +xml::UpdateResponseResult CheckSystemRequirements( + const xml::UpdateResponse* update_response, const CString& language) { + ASSERT1(update_response); + + const xml::response::SystemRequirements& sys_req( + update_response->response().sys_req); + StringFormatter formatter(language); + CString text; + + if (IsPlatformCompatible(sys_req.platform) && + IsArchCompatible(sys_req.arch) && + IsOSVersionCompatible(sys_req.min_os_version)) { + return std::make_pair(S_OK, CString()); + } + + VERIFY1(SUCCEEDED(formatter.LoadString(IDS_OS_NOT_SUPPORTED, &text))); + return std::make_pair(GOOPDATE_E_OS_NOT_SUPPORTED, text); +} + + } // namespace update_response_utils } // namespace omaha diff --git a/omaha/goopdate/update_response_utils.h b/omaha/goopdate/update_response_utils.h index 3b249d8be..70767bfbf 100644 --- a/omaha/goopdate/update_response_utils.h +++ b/omaha/goopdate/update_response_utils.h @@ -62,6 +62,14 @@ bool IsOmahaUpdateAvailable(const xml::UpdateResponse* update_response); HRESULT ApplyExperimentLabelDeltas(bool is_machine, const xml::UpdateResponse* update_response); +// If a element exists in the response, this function +// checks compatibility with the currently running system. Returns +// S_OK or GOOPDATE_E_OS_NOT_SUPPORTED for the HRESULT in UpdateResponseResult. +// The absence of the element indicates that the +// UpdateResponse is valid for the current system. +xml::UpdateResponseResult CheckSystemRequirements( + const xml::UpdateResponse* update_response, const CString& language); + } // namespace update_response_utils } // namespace omaha diff --git a/omaha/goopdate/update_response_utils_unittest.cc b/omaha/goopdate/update_response_utils_unittest.cc index 96336a829..dcc4bc23d 100644 --- a/omaha/goopdate/update_response_utils_unittest.cc +++ b/omaha/goopdate/update_response_utils_unittest.cc @@ -17,6 +17,7 @@ #include "omaha/base/app_util.h" #include "omaha/base/constants.h" #include "omaha/base/error.h" +#include "omaha/base/system_info.h" #include "omaha/goopdate/app_unittest_base.h" #include "omaha/goopdate/resource_manager.h" #include "omaha/goopdate/update_response_utils.h" @@ -48,6 +49,9 @@ const TCHAR* const GOOPDATE_E_HW_NOT_SUPPORTEDString = _T("Installation failed because your computer does not meet minimum ") _T("hardware requirements for Google Chrome."); +const TCHAR* const GOOPDATE_E_OS_NOT_SUPPORTEDString = + _T("Installation failed because your version of Windows is not supported."); + const UpdateResponseResult kUpdateAvailableResult = std::make_pair(S_OK, CString()); @@ -59,6 +63,12 @@ const UpdateResponseResult kHwNotSupported = std::make_pair( GOOPDATE_E_HW_NOT_SUPPORTED, CString(GOOPDATE_E_HW_NOT_SUPPORTEDString)); +const UpdateResponseResult kOk = std::make_pair(S_OK, CString()); + +const UpdateResponseResult kOsNotSupported = std::make_pair( + GOOPDATE_E_OS_NOT_SUPPORTED, + CString(GOOPDATE_E_OS_NOT_SUPPORTEDString)); + } // namespace @@ -281,6 +291,100 @@ TEST_F(UpdateResponseUtilsGetResultTest, HwNotSupported) { _T("en"))); } +TEST_F(UpdateResponseUtilsGetResultTest, SystemRequirementsElement_Compatible) { + xml::response::Response response; + xml::response::SystemRequirements& sys_req = response.sys_req; + sys_req.platform = _T("win"); + sys_req.arch = _T("x86"); + sys_req.min_os_version = _T("6.0"); + + SetResponseForUnitTest(update_response_.get(), response); + + EXPECT_TRUE(kOk == CheckSystemRequirements(update_response_.get(), _T("en"))); +} + +TEST_F(UpdateResponseUtilsGetResultTest, + SystemRequirementsElement_PlatformMismatch) { + xml::response::Response response; + xml::response::SystemRequirements& sys_req = response.sys_req; + sys_req.platform = _T("mac"); + sys_req.arch = _T("x86"); + sys_req.min_os_version = _T("6.0"); + + SetResponseForUnitTest(update_response_.get(), response); + + EXPECT_TRUE(kOsNotSupported == + CheckSystemRequirements(update_response_.get(), _T("en"))); +} + +TEST_F(UpdateResponseUtilsGetResultTest, + SystemRequirementsElement_ArchUnknown) { + xml::response::Response response; + xml::response::SystemRequirements& sys_req = response.sys_req; + sys_req.platform = _T("win"); + sys_req.arch = _T("unknown"); + sys_req.min_os_version = _T("6.0"); + + SetResponseForUnitTest(update_response_.get(), response); + + EXPECT_TRUE(kOsNotSupported == + CheckSystemRequirements(update_response_.get(), _T("en"))); +} + +TEST_F(UpdateResponseUtilsGetResultTest, SystemRequirementsElement_Archx86) { + xml::response::Response response; + xml::response::SystemRequirements& sys_req = response.sys_req; + sys_req.platform = _T("win"); + sys_req.arch = _T("x86"); + sys_req.min_os_version = _T("6.0"); + + SetResponseForUnitTest(update_response_.get(), response); + + EXPECT_TRUE(kOk == CheckSystemRequirements(update_response_.get(), _T("en"))); +} + +TEST_F(UpdateResponseUtilsGetResultTest, SystemRequirementsElement_Archx64) { + xml::response::Response response; + xml::response::SystemRequirements& sys_req = response.sys_req; + sys_req.platform = _T("win"); + sys_req.arch = _T("x64"); + sys_req.min_os_version = _T("6.0"); + + SetResponseForUnitTest(update_response_.get(), response); + + EXPECT_TRUE( + (SystemInfo::GetProcessorArchitecture() == PROCESSOR_ARCHITECTURE_AMD64 ? + kOk : kOsNotSupported) + == CheckSystemRequirements(update_response_.get(), _T("en"))); +} + +TEST_F(UpdateResponseUtilsGetResultTest, + SystemRequirementsElement_ReallyHighSystemRequirementsVersion) { + xml::response::Response response; + xml::response::SystemRequirements& sys_req = response.sys_req; + sys_req.platform = _T("win"); + sys_req.arch = _T("x86"); + sys_req.min_os_version = _T("60.0"); + + SetResponseForUnitTest(update_response_.get(), response); + + EXPECT_TRUE(kOsNotSupported == + CheckSystemRequirements(update_response_.get(), _T("en"))); +} + +TEST_F(UpdateResponseUtilsGetResultTest, + SystemRequirementsElement_ReallyLowSystemRequirementsVersion) { + xml::response::Response response; + xml::response::SystemRequirements& sys_req = response.sys_req; + sys_req.platform = _T("win"); + sys_req.arch = _T("x86"); + sys_req.min_os_version = _T("0.01"); + + SetResponseForUnitTest(update_response_.get(), response); + + EXPECT_TRUE(kOk == CheckSystemRequirements(update_response_.get(), _T("en"))); +} + INSTANTIATE_TEST_CASE_P(IsMachine, UpdateResponseUtilsTest, ::testing::Bool()); TEST_P(UpdateResponseUtilsTest, BuildApp_Cohorts) { diff --git a/omaha/goopdate/worker.cc b/omaha/goopdate/worker.cc index 74a2abef4..c7bcc9636 100644 --- a/omaha/goopdate/worker.cc +++ b/omaha/goopdate/worker.cc @@ -199,7 +199,7 @@ HRESULT SendOemInstalledPing(bool is_machine, const CString& session_id) { Ping ping(is_machine, session_id, CString()); ping.LoadAppDataFromRegistry(oem_installed_apps); ping.BuildAppsPing(oem_ping_event); - hr = ping.Send(false); + hr = SendReliablePing(&ping, false); if (FAILED(hr)) { CORE_LOG(L3, (_T("[SendOemInstalledPing failed][0x%08x]"), hr)); return hr; @@ -222,7 +222,7 @@ void SendCupFailurePing(bool is_machine, ping.LoadOmahaDataFromRegistry(); ping.BuildOmahaPing(NULL, NULL, ping_event); - HRESULT hr = ping.Send(false); + HRESULT hr = SendReliablePing(&ping, false); if (FAILED(hr)) { CORE_LOG(LW, (_T("[SendCupFailurePing failed][0x%x]"), hr)); } @@ -491,17 +491,16 @@ void Worker::CheckForUpdateHelper(AppBundle* app_bundle, app_bundle, hr, update_response.get()); - - // If we used HTTPS at any time during this update check, and the HTTPS - // attempt failed due to a CUP authentication failure, send a debug ping. - if (FAILED(hr) && app_bundle->update_check_client()->http_used_ssl()) { - const HRESULT ssl_hr = app_bundle->update_check_client()->http_ssl_result(); - if (IsCupError(ssl_hr)) { - CORE_LOG(L3, (_T("[CUP-via-HTTPS failed.][%#08x][%#08x]"), hr, ssl_hr)); + if (IsCupError(hr)) { + CORE_LOG(L3, (_T("[CUP failed][%#08x]"), hr)); + // Only send the CUP debug ping when there is no "retry after" in effect. + const int retry_after_sec( + app_bundle->update_check_client()->retry_after_sec()); + if (retry_after_sec <= 0) { internal::SendCupFailurePing(is_machine_, app_bundle->session_id(), app_bundle->install_source(), - ssl_hr); + hr); } } @@ -963,9 +962,6 @@ HRESULT Worker::DoUpdateCheck(AppBundle* app_bundle, CORE_LOG(L3, (_T("[Update check HTTP trace][%s]"), app_bundle->update_check_client()->http_trace())); - PersistRetryAfter( - app_bundle->update_check_client()->http_xretryafter_header_value()); - if (FAILED(hr)) { metric_updatecheck_failed_ms.AddSample(update_check_timer.GetElapsedMs()); @@ -977,17 +973,6 @@ HRESULT Worker::DoUpdateCheck(AppBundle* app_bundle, app_bundle->update_check_client()->http_trace(), is_machine_); - // If we got a response that appears to be from the official Omaha server, - // but doesn't validate for some reason, it might have a X-DayStart or - // X-Daynum header. If so, assume that we delivered the last-active and - // roll-call reports correctly, and roll the counters on our end. (On a - // successful network call, the App objects will do it themselves when they - // transition out of the CheckingForUpdate state.) - PersistUpdateCheckSuccessfullySent( - app_bundle, - app_bundle->update_check_client()->http_xdaynum_header_value(), - app_bundle->update_check_client()->http_xdaystart_header_value()); - // TODO(omaha3): Omaha 2 would launch a web browser here for installs by // calling goopdate_utils::LaunchBrowser(). Browser launch needs to be in // the client but it currently has no way of knowing that it was a network @@ -1014,6 +999,8 @@ void Worker::DoPostUpdateCheck(AppBundle* app_bundle, is_machine_, update_response))); + PersistRetryAfter(app_bundle->update_check_client()->retry_after_sec()); + for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) { App* app = app_bundle->GetApp(i); app->PostUpdateCheck(update_check_result, update_response); @@ -1033,52 +1020,20 @@ void Worker::DoPostUpdateCheck(AppBundle* app_bundle, void Worker::PersistRetryAfter(int retry_after_sec) const { CORE_LOG(L6, (_T("[Worker::PersistRetryAfter][%d]"), retry_after_sec)); + // Registry writes to HKLM need admin. + ASSERT1(!is_machine_ || vista_util::IsUserAdmin()); + if (retry_after_sec <= 0) { - ConfigManager::Instance()->SetRetryAfterTime(is_machine_, 0); return; } - const int kMaxRetryAfterSeconds = 5 * kSecondsPerHour; - if (retry_after_sec > kMaxRetryAfterSeconds) { - retry_after_sec = kSecondsPerDay; - } - + ASSERT1(retry_after_sec <= kSecondsPerDay); const uint32 now_sec = Time64ToInt32(GetCurrent100NSTime()); DWORD retry_after_time_sec = now_sec + retry_after_sec; ConfigManager::Instance()->SetRetryAfterTime(is_machine_, retry_after_time_sec); } -void Worker::PersistUpdateCheckSuccessfullySent(AppBundle* app_bundle, - int daynum, - int daystart) { - ASSERT1(app_bundle); - - // This function will be called even when network request fails. In this case, - // Omaha looks into response headers for relevant values. |daynum| or - // |daystart|will be -1 if the corresponding header value is absent. Client - // should not persist if either value is -1. - if (daystart == -1 || daynum == -1) { - return; - } - - ASSERT1(daystart >= 0); - ASSERT1(daynum >= kMinDaysSinceDatum); - ASSERT1(daynum <= kMaxDaysSinceDatum); - - CORE_LOG(LE, (_T("[Worker::PersistUpdateCheckSuccessfullySent][%d]"), - daystart)); - - AppManager& app_manager = *AppManager::Instance(); - - for (size_t i = 0; i != app_bundle->GetNumberOfApps(); ++i) { - App* app = app_bundle->GetApp(i); - app->set_day_of_last_response(daynum); - VERIFY1(SUCCEEDED(app_manager.PersistUpdateCheckSuccessfullySent( - *app, daynum, daystart))); - } -} - // Creates a thread pool work item for deferred execution of deferred_function. // The thread pool owns this callback object. HRESULT Worker::QueueDeferredFunctionCall0( diff --git a/omaha/goopdate/worker.h b/omaha/goopdate/worker.h index e860107d2..b4f77b1e1 100644 --- a/omaha/goopdate/worker.h +++ b/omaha/goopdate/worker.h @@ -163,9 +163,6 @@ class Worker : public WorkerModelInterface, public ShutdownCallback { void PersistRetryAfter(int retry_after_sec) const; - void PersistUpdateCheckSuccessfullySent( - AppBundle* app_bundle, int daynum, int daystart); - HRESULT QueueDeferredFunctionCall0( shared_ptr app_bundle, void (Worker::*deferred_function)(shared_ptr)); diff --git a/omaha/goopdate/worker_unittest.cc b/omaha/goopdate/worker_unittest.cc index 91d5099b6..b91600ce4 100644 --- a/omaha/goopdate/worker_unittest.cc +++ b/omaha/goopdate/worker_unittest.cc @@ -143,7 +143,7 @@ class MockWebServicesClient : public WebServicesClientInterface { int()); MOCK_CONST_METHOD0(http_xdaynum_header_value, int()); - MOCK_CONST_METHOD0(http_xretryafter_header_value, + MOCK_CONST_METHOD0(retry_after_sec, int()); }; @@ -393,7 +393,7 @@ TEST_F(WorkerMockedManagersTest, CheckForUpdateAsync) { .WillByDefault(Return(_T(""))); EXPECT_CALL(*mock_web_services_client_, http_trace()) .Times(AnyNumber()); - EXPECT_CALL(*mock_web_services_client_, http_xretryafter_header_value()) + EXPECT_CALL(*mock_web_services_client_, retry_after_sec()) .Times(1); __mutexBlock(worker_->model()->lock()) { @@ -571,7 +571,7 @@ TEST_F(WorkerMockedManagersTest, UpdateAllAppsAsync) { .WillByDefault(Return(_T(""))); EXPECT_CALL(*mock_web_services_client_, http_trace()) .Times(AnyNumber()); - EXPECT_CALL(*mock_web_services_client_, http_xretryafter_header_value()) + EXPECT_CALL(*mock_web_services_client_, retry_after_sec()) .Times(1); __mutexBlock(worker_->model()->lock()) { diff --git a/omaha/internal/grit/goopdateres.grd b/omaha/internal/grit/goopdateres.grd index ab6db3dde..a59bda3a1 100644 --- a/omaha/internal/grit/goopdateres.grd +++ b/omaha/internal/grit/goopdateres.grd @@ -329,7 +329,7 @@ - Egads! Download failed. Retrying... %1!d!5 second(s) + Egads! Download failed. Retrying... %1!d!5 second(s) remaining @@ -337,15 +337,15 @@ - Downloading... %1!d!56 second(s) + Downloading... %1!d!56 second(s) remaining - Downloading... %1!d!13 minute(s) + Downloading... %1!d!13 minute(s) remaining - Downloading... %1!d!2 hour(s) + Downloading... %1!d!2 hour(s) remaining diff --git a/omaha/net/cup_ecdsa_pubkey.6.h b/omaha/net/cup_ecdsa_pubkey.6.h new file mode 100644 index 000000000..6ec1d7521 --- /dev/null +++ b/omaha/net/cup_ecdsa_pubkey.6.h @@ -0,0 +1,31 @@ +// Copyright 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// ======================================================================== +// +// CUP-ECDSA public keys consist of a byte array, 66 bytes long, containing: +// * The key ID (one byte) +// * The public key in X9.62 uncompressed encoding (65 bytes): +// * Uncompressed header byte (0x04) +// * Gx coordinate (256-bit integer, big-endian) +// * Gy coordinate (256-bit integer, big-endian) +{0x06, +0x04, +0x08, 0x40, 0xd2, 0x45, 0xc6, 0x4f, 0x2a, 0xff, +0x24, 0xe0, 0x91, 0x18, 0x6c, 0x5e, 0xcc, 0x27, +0x1c, 0x71, 0xe7, 0xa9, 0xbe, 0xc7, 0xc6, 0x7e, +0xb2, 0xf8, 0x39, 0x80, 0x19, 0x91, 0x5f, 0x52, +0x7c, 0x03, 0xd0, 0xd8, 0x44, 0xbe, 0x8d, 0xbc, +0x59, 0x0d, 0x72, 0x67, 0x11, 0xb5, 0x23, 0x5e, +0x99, 0x49, 0xbb, 0xfe, 0x2a, 0xab, 0x52, 0x7c, +0x5a, 0x69, 0xd9, 0x2a, 0x71, 0x64, 0x8e, 0x0f}; diff --git a/omaha/net/cup_ecdsa_request.cc b/omaha/net/cup_ecdsa_request.cc index f141e591c..cb491b729 100644 --- a/omaha/net/cup_ecdsa_request.cc +++ b/omaha/net/cup_ecdsa_request.cc @@ -42,7 +42,7 @@ namespace omaha { namespace internal { const uint8 CupEcdsaRequestImpl::kCupProductionPublicKey[] = -#include "omaha/net/cup_ecdsa_pubkey.5.h" +#include "omaha/net/cup_ecdsa_pubkey.6.h" ; // NOLINT const uint8 CupEcdsaRequestImpl::kCupTestPublicKey[] = diff --git a/omaha/net/cup_ecdsa_utils_unittest.cc b/omaha/net/cup_ecdsa_utils_unittest.cc index df0345612..21041902d 100644 --- a/omaha/net/cup_ecdsa_utils_unittest.cc +++ b/omaha/net/cup_ecdsa_utils_unittest.cc @@ -491,7 +491,7 @@ TEST(EcdsaPublicKey, DecodeFromBuffer_ProdKey) { EcdsaPublicKey key; uint8 kProdKey[] = -#include "omaha/net/cup_ecdsa_pubkey.5.h" +#include "omaha/net/cup_ecdsa_pubkey.6.h" ; // NOLINT key.DecodeFromBuffer(kProdKey); diff --git a/omaha/net/network_request_impl.cc b/omaha/net/network_request_impl.cc index 87be6ce32..486900adf 100644 --- a/omaha/net/network_request_impl.cc +++ b/omaha/net/network_request_impl.cc @@ -552,10 +552,11 @@ HRESULT NetworkRequestImpl::DoSendHttpRequest( cur_http_request_->GetResponse().swap(*response); CString retry_after_header; - HRESULT hr = QueryHeadersString(WINHTTP_QUERY_CUSTOM, - kHeaderXRetryAfter, - &retry_after_header); - if (SUCCEEDED(hr) && !retry_after_header.IsEmpty()) { + if (IsHttpsUrl(url_) && + SUCCEEDED(QueryHeadersString(WINHTTP_QUERY_CUSTOM, + kHeaderXRetryAfter, + &retry_after_header)) && + !retry_after_header.IsEmpty()) { retry_after_seconds_ = String_StringToInt(retry_after_header); } diff --git a/omaha/net/network_request_impl.h b/omaha/net/network_request_impl.h index 1cf41cf0b..bffd31211 100644 --- a/omaha/net/network_request_impl.h +++ b/omaha/net/network_request_impl.h @@ -195,11 +195,12 @@ class NetworkRequestImpl { HRESULT last_hr_; int last_http_status_code_; - // This member stores the value of the optional X-Retry-After header. If the - // server sends a positive value in seconds for this header, the request will - // stop processing fallbacks and will return from the + // Stores the last valid value of the optional X-Retry-After header or -1 if + // the header was not present in the request. Only HTTPS X-Retry-After header + // values are respected. + // If the server sends a positive value in seconds for this header, the + // request will stop processing fallbacks and will return from the // NetworkRequestImpl::DoSendWithRetries() call immediately. - // The default value is -1 when the header is not found. int retry_after_seconds_; // The current retry count and delay between retries, defined by the outermost diff --git a/omaha/net/simple_request_unittest.cc b/omaha/net/simple_request_unittest.cc index 9e0c56834..c26e4946b 100644 --- a/omaha/net/simple_request_unittest.cc +++ b/omaha/net/simple_request_unittest.cc @@ -100,7 +100,9 @@ class SimpleRequestTest : public testing::Test { void SimpleDownloadFilePauseAndResume(const CString& url, const CString& filename, const ProxyConfig& config); - void SimpleDownloadFileCancellation(const CString& filename, bool do_cancel); + // Returns the result of the Send call. + HRESULT SimpleDownloadFileCancellation(const CString& filename, + bool do_cancel); void SimpleGetHostNotFound(const CString& url, const ProxyConfig& config); void SimpleGetFileNotFound(const CString& url, const ProxyConfig& config); @@ -237,7 +239,7 @@ void SimpleRequestTest::SimpleDownloadFilePauseAndResume( } } -void SimpleRequestTest::SimpleDownloadFileCancellation( +HRESULT SimpleRequestTest::SimpleDownloadFileCancellation( const CString& filename, bool do_cancel) { SimpleRequest simple_request; PrepareRequest(kBigFileUrl, ProxyConfig(), &simple_request); @@ -259,6 +261,8 @@ void SimpleRequestTest::SimpleDownloadFileCancellation( } else { EXPECT_HRESULT_SUCCEEDED(hr); } + + return hr; } void SimpleRequestTest::SimpleGetHostNotFound(const CString& url, @@ -512,9 +516,11 @@ TEST_F(SimpleRequestTest, Cancel_ShouldDeleteTempFile) { // Verify that cancellation should remove partially downloaded file. bool do_cancel = true; - SimpleDownloadFileCancellation(temp_file, do_cancel); - EXPECT_EQ(INVALID_FILE_ATTRIBUTES, ::GetFileAttributes(temp_file)); - EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError()); + HRESULT hr = SimpleDownloadFileCancellation(temp_file, do_cancel); + if (FAILED(hr)) { + EXPECT_EQ(INVALID_FILE_ATTRIBUTES, ::GetFileAttributes(temp_file)); + EXPECT_EQ(ERROR_FILE_NOT_FOUND, ::GetLastError()); + } // Verify that target file is preserved if download is not cancelled. do_cancel = false; diff --git a/omaha/recovery/client/google_update_recovery_unittest.cc b/omaha/recovery/client/google_update_recovery_unittest.cc index 9f9132b69..478d6058a 100644 --- a/omaha/recovery/client/google_update_recovery_unittest.cc +++ b/omaha/recovery/client/google_update_recovery_unittest.cc @@ -127,6 +127,16 @@ CString GetTmp() { return temp_dir; } +CString MakeTestFilepath(const CString& relpath) { + // This function assumes that the Omaha unit test program runs from + // a staging directory, which contains a unittest_support sub-directory + // for test files. + const CString staging_dir(app_util::GetCurrentModuleDirectory()); + CString filepath(staging_dir); + EXPECT_TRUE(::PathAppend(CStrBuf(filepath, MAX_PATH), relpath)); + return filepath; +} + } // namespace HRESULT VerifyFileSignature(const CString& filename); @@ -831,54 +841,38 @@ TEST_F(GoogleUpdateRecoveryTest, FixGoogleUpdate_FileCollision) { // VerifyFileSignature Tests // TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_SignedValid) { - CString executable_full_path(app_util::GetCurrentModuleDirectory()); - EXPECT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH), - kArgumentSavingExecutableRelativePath)); + const CString executable_full_path(MakeTestFilepath( + kArgumentSavingExecutableRelativePath)); EXPECT_TRUE(File::Exists(executable_full_path)); EXPECT_HRESULT_SUCCEEDED(VerifyFileSignature(executable_full_path)); } TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_NotSigned) { - const TCHAR kUnsignedExecutable[] = _T("GoogleUpdate_unsigned.exe"); - - CString executable_full_path(app_util::GetCurrentModuleDirectory()); - EXPECT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH), - kUnsignedExecutable)); + const CString executable_full_path(MakeTestFilepath( + _T("GoogleUpdate_unsigned.exe"))); EXPECT_TRUE(File::Exists(executable_full_path)); EXPECT_EQ(TRUST_E_NOSIGNATURE, VerifyFileSignature(executable_full_path)); } // The file is signed with an old cerificate not present in the pin list. TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_NotTrusted) { - const TCHAR kRelativePath[] = - _T("unittest_support\\GoogleUpdate_old_signature.exe"); - - CString executable_full_path(app_util::GetCurrentModuleDirectory()); - EXPECT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH), - kRelativePath)); + const CString executable_full_path(MakeTestFilepath( + _T("unittest_support\\GoogleUpdate_old_signature.exe"))); EXPECT_TRUE(File::Exists(executable_full_path)); EXPECT_EQ(GOOPDATE_E_SIGNATURE_NOT_TRUSTED_PIN, VerifyFileSignature(executable_full_path)); } TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_UntrustedChain) { - const TCHAR kUntrustedChainExecutable[] = - _T("unittest_support\\SaveArguments_OmahaTestSigned.exe"); - - CString executable_full_path(app_util::GetCurrentModuleDirectory()); - EXPECT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH), - kUntrustedChainExecutable)); + const CString executable_full_path(MakeTestFilepath( + _T("unittest_support\\SaveArguments_OmahaTestSigned.exe"))); EXPECT_TRUE(File::Exists(executable_full_path)); EXPECT_EQ(CERT_E_UNTRUSTEDROOT, VerifyFileSignature(executable_full_path)); } TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_HashFails) { - const TCHAR kCorruptedExecutable[] = - _T("unittest_support\\GoogleUpdate_corrupted.exe"); - - CString executable_full_path(app_util::GetCurrentModuleDirectory()); - EXPECT_TRUE(::PathAppend(CStrBuf(executable_full_path, MAX_PATH), - kCorruptedExecutable)); + const CString executable_full_path(MakeTestFilepath( + _T("unittest_support\\GoogleUpdate_corrupted.exe"))); EXPECT_TRUE(File::Exists(executable_full_path)); EXPECT_EQ(TRUST_E_BAD_DIGEST, VerifyFileSignature(executable_full_path)); } @@ -912,41 +906,47 @@ TEST_F(GoogleUpdateRecoveryTest, VerifyFileSignature_BadFilenames) { // VerifyRepairFileMarkup Tests // TEST_F(GoogleUpdateRecoveryTest, VerifyRepairFileMarkup_ValidMarkup) { - const TCHAR kExecutableWithMarkup[] = - _T("unittest_support\\SaveArguments.exe"); - EXPECT_HRESULT_SUCCEEDED(VerifyRepairFileMarkup(kExecutableWithMarkup)); + EXPECT_HRESULT_SUCCEEDED(VerifyRepairFileMarkup(MakeTestFilepath( + _T("unittest_support\\SaveArguments.exe")))); } TEST_F(GoogleUpdateRecoveryTest, VerifyRepairFileMarkup_InvalidMarkups) { const TCHAR kNoResourcesExecutable[] = _T("unittest_support\\SaveArguments_unsigned_no_resources.exe"); + EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_RESOURCE_DATA_NOT_FOUND), - VerifyRepairFileMarkup(kNoResourcesExecutable)); + VerifyRepairFileMarkup(MakeTestFilepath(kNoResourcesExecutable))); const TCHAR kResourcesButNoMarkupExecutable[] = _T("GoogleUpdate.exe"); EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_RESOURCE_TYPE_NOT_FOUND), - VerifyRepairFileMarkup(kResourcesButNoMarkupExecutable)); + VerifyRepairFileMarkup(MakeTestFilepath( + kResourcesButNoMarkupExecutable))); const TCHAR kWrongMarkupResourceNameExecutable[] = _T("unittest_support\\SaveArguments_unsigned_wrong_resource_name.exe"); EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_RESOURCE_NAME_NOT_FOUND), - VerifyRepairFileMarkup(kWrongMarkupResourceNameExecutable)); + VerifyRepairFileMarkup(MakeTestFilepath( + kWrongMarkupResourceNameExecutable))); const TCHAR kWrongMarkupSizeExecutable[] = _T("unittest_support\\SaveArguments_unsigned_wrong_markup_size.exe"); - EXPECT_EQ(E_UNEXPECTED, VerifyRepairFileMarkup(kWrongMarkupSizeExecutable)); + EXPECT_EQ(E_UNEXPECTED, + VerifyRepairFileMarkup(MakeTestFilepath( + kWrongMarkupSizeExecutable))); const TCHAR kWrongMarkupValueExecutable[] = _T("unittest_support\\SaveArguments_unsigned_wrong_markup_value.exe"); - EXPECT_EQ(E_UNEXPECTED, VerifyRepairFileMarkup(kWrongMarkupValueExecutable)); + EXPECT_EQ(E_UNEXPECTED, + VerifyRepairFileMarkup(MakeTestFilepath( + kWrongMarkupValueExecutable))); } TEST_F(GoogleUpdateRecoveryTest, VerifyRepairFileMarkup_BadFilenames) { const TCHAR kMissingFile[] = _T("NoSuchFile.exe"); - EXPECT_EQ(FALSE, ::PathFileExists(kMissingFile)); + EXPECT_EQ(FALSE, ::PathFileExists(MakeTestFilepath(kMissingFile))); EXPECT_EQ(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND), - VerifyRepairFileMarkup(kMissingFile)); - EXPECT_HRESULT_FAILED(VerifyRepairFileMarkup(_T(""))); + VerifyRepairFileMarkup(MakeTestFilepath(kMissingFile))); + EXPECT_HRESULT_FAILED(VerifyRepairFileMarkup(MakeTestFilepath(_T("")))); } // diff --git a/omaha/setup/setup.cc b/omaha/setup/setup.cc index 3d050a73a..095168010 100644 --- a/omaha/setup/setup.cc +++ b/omaha/setup/setup.cc @@ -1361,7 +1361,7 @@ HRESULT Setup::SendUninstallPing() { apps_uninstall_ping.LoadAppDataFromRegistry(uninstalled_apps); apps_uninstall_ping.BuildAppsPing(uninstall_ping_event); - hr = apps_uninstall_ping.Send(false); + hr = SendReliablePing(&apps_uninstall_ping, false); if (FAILED(hr)) { CORE_LOG(LE, (_T("[SendUninstallPing: failed to send app uninstall ping]") _T("[0x%08x]"), hr)); @@ -1376,7 +1376,7 @@ HRESULT Setup::SendUninstallPing() { omaha_uninstall_ping.BuildOmahaPing(current_omaha_version, next_omaha_version, uninstall_ping_event); - hr = omaha_uninstall_ping.Send(false); + hr = SendReliablePing(&omaha_uninstall_ping, false); if (SUCCEEDED(hr)) { // Clears the registry after ping is sent successfully. uninstalled_apps.clear(); diff --git a/omaha/setup/setup_metrics.cc b/omaha/setup/setup_metrics.cc index d9e1e09f8..570f93717 100644 --- a/omaha/setup/setup_metrics.cc +++ b/omaha/setup/setup_metrics.cc @@ -106,5 +106,8 @@ DEFINE_METRIC_count(setup_uac_succeeded); DEFINE_METRIC_count(setup_user_app_admin); DEFINE_METRIC_count(setup_machine_app_non_admin); +DEFINE_METRIC_integer(omaha_last_error_code); +DEFINE_METRIC_integer(omaha_last_extra_code); + } // namespace omaha diff --git a/omaha/setup/setup_metrics.h b/omaha/setup/setup_metrics.h index 991230efa..46957750b 100644 --- a/omaha/setup/setup_metrics.h +++ b/omaha/setup/setup_metrics.h @@ -203,6 +203,9 @@ DECLARE_METRIC_count(setup_user_app_admin); // How many times Setup attempted to install machine app as non-admin on