Commit graph

53 commits

Author SHA1 Message Date
Keith Mok
e8600253ac Set a property if seed binding is enabled.
For vehicle binding seed atest

Bug: 157501579
Test: atest vehicle-binding-seed-sh
Change-Id: Ie1dad1735193ce722ec036e38f826a6b90e94526
2021-09-01 22:06:10 +00:00
Eric Biggers
d86a8abec7 Replace most references to Keymaster with Keystore
Now that vold uses Keystore2 rather than the Keymaster HAL directly, and
also the new version of Keymaster is called "KeyMint" instead, replace
most of the references to Keymaster in vold with Keystore.

(I decided not to include the "2" in most places, as it seemed
unnecessarily precise in most places, and it would be something that
might need to keep being updated.  Only Keystore.{cpp,h} really need to
care about the version number.)

I didn't rename many things in cryptfs.cpp, as that file will be going
away soon anyway.  I also left "wait_for_keymaster" and "vdc keymaster
earlyBootEnded" as-is for now, as those are referenced outside vold.

Bug: 183669495
Change-Id: I92cd648fae09f8c9769f7cf34dbf6c6e956be4e8
2021-06-15 12:07:15 -07:00
Satya Tangirala
351a4af716 Don't export storeKey(), and update comments
storeKey() is no longer used outside KeyStorage.cpp, so make it a static
function.  Also fix the documentation for storeKey() (e.g. it's no
longer safe to directly move/rename directories created by storeKey() --
one must use RenameKeyDir() instead).

No functional changes.

[ebiggers@ - cleaned up slightly from satyat@'s original change]

Bug: 190398249
Change-Id: I85918359e77bef414dfddfe5ded30fcde6514013
2021-06-08 15:57:31 -07:00
Satya Tangirala
0f890a93e1 Always use RenameKeyDir() when moving/renaming key directories
Make fixate_user_ce_key() use RenameKeyDir() to rename key directories
so that any deferred commits for these directories are also updated
appropriately.

This fixes a potential lost Keymaster key upgrade if a key were to be
re-wrapped while a user data checkpoint is pending.  This isn't a huge
issue as the key will just get upgraded again, but this should be fixed.

[ebiggers@ - cleaned up slightly from satyat@'s original change]

Bug: 190398249
Change-Id: Ic6c5b4468d07ab335368e3d373916145d096af01
2021-06-08 15:57:31 -07:00
Eric Biggers
107d21d484 Make RenameKeyDir() use IsSameFile()
Comparing paths is error-prone (e.g. "/foo/bar" vs "/foo//bar"), so
entries in key_dirs_to_commit are compared using inode and device
number.  However RenameKeyDir() breaks this rule and compares raw paths.

Avoid this quirk by finding the entry in the list to replace before
doing the rename.

This doesn't fix any known problem, as vold is fairly consistent with
its paths in practice; this is just a robustness improvement.

Bug: 190398249
Change-Id: I3ce2c0119cb2012ac9d12849570e56600bc23867
2021-06-08 15:57:31 -07:00
Satya Tangirala
9475b11a1e Fix bug with deferred commits for key upgrades in temporary directories
storeKeyAtomically() stores keys in a temp directory before renaming
that directory to the real target directory. However when the key is
stored in the temporary directory, the Keymaster storage key might get
upgraded, and it's possible that the temp directory is scheduled for a
deferred commit. storeKeyAtomically() renames that temp directory, but
doesn't update the list of directories marked for deferred commit.

This patch fixes this by removing the temp directory from the list and
adding the real target directory to that list instead.

This bug was found when trying to switch from using the guest keymint to
using the host remote keymint implementation on cuttlefish
(aosp/1701925).  The device triggers this bug (and boots to recovery)
when aosp/1701925 is cherry-picked.

Co-Developed-By: Eric Biggers <ebiggers@google.com>
Test: Cuttlefish boots with and without aosp/1701925
Change-Id: I3b6fd6ad32ed415da94423cca6f5a121c16472f2
2021-05-13 11:21:23 -07:00
Satya Tangirala
6b98fb6122 Remove unused constants and cleanup KeyStorage.cpp
Now that the salt and hardware auth token related code has been removed,
we can remove the associated (and now unused) constants.

Also cleanup some comments and remove includes related to hardware auth
token support.

Bug: 181910578
Test: Cuttlefish boots.
Change-Id: I3733d5c6bbf6989adc165c554ee53faa2484f4b6
2021-05-12 13:05:35 -07:00
Satya Tangirala
478cea9783 Remove unused parameter "salt" from stretchSecret()
stretchSecret() no longer uses the "salt" parameter, so remove it and
simplify callers

Bug: 181910578
Test: Cuttlefish boots.
Change-Id: Ic2d0742b22b98a66da37f435e274c9d385b8e188
2021-05-12 13:05:35 -07:00
Satya Tangirala
e8de4ffd73 Make vold use keystore2 instead of keymaster
Make vold use keystore2 for all its operations instead of directly using
keymaster. This way, we won't have any clients that bypass keystore2,
and we'll no longer need to reserve a keymaster operation for vold.

Note that we now hardcode "SecurityLevel::TRUSTED_ENVIRONMENT" (TEE)
when talking to Keystore2 since Keystore2 only allows TEE and STRONGBOX.
Keystore2 presents any SOFTWARE implementation as a TEE to callers when
no "real" TEE is present. As far as storage encryption is concerned,
there's no advantage to using a STRONGBOX when a "real" TEE is present,
and a STRONGBOX can't be present if a "real" TEE isn't, so asking
Keystore2 for a TEE is the best we can do in any situation.

The difference in behaviour only really affects the full disk encryption
code in cryptfs.cpp, which used to explicitly check that the keymaster
device is a "real" TEE (as opposed to a SOFTWARE implementation) before
using it (it can no longer do so since Keystore2 doesn't provide a way
to do this).

A little code history digging (7c49ab0a0b in particular) shows that
cryptfs.cpp cared about two things when using a keymaster.
 - 1) that the keys generated by the keymaster were "standalone" keys -
      i.e. that the keymaster could operate on those keys without
      requiring /data or any other service to be available.
 - 2) that the keymaster was a non-SOFTWARE implementation so that things
      would still work in case a "real" TEE keymaster was ever somehow
      added to the device after first boot.

Today, all "real" TEE keymasters always generate "standalone" keys, and
a TEE has been required in Android devices since at least Android N. The
only two exceptions are Goldfish and ARC++, which have SOFTWARE
keymasters, but both those keymasters also generate "standalone" keys.

We're also no longer worried about possibly adding a "real" TEE KM to
either of those devices after first boot. So there's no longer a reason
cryptfs.cpp can't use the SOFTWARE keymaster on those devices.

There's also already an upgrade path in place (see
test_mount_encrypted_fs() in cryptfs.cpp) to upgrade the kdf that's
being used once a TEE keymaster is added to the device. So it's safe for
cryptfs.cpp to ask for a TEE keymaster from Keystore2 and use it
blindly, without checking whether or not it's a "real" TEE, which is why
Keymaster::isSecure() just returns true now. A future patch will remove
that function and simplify its callers.

Bug: 181910578
Test: cuttlefish and bramble boot. Adding, switching between, stopping
      and removing users work.
Change-Id: Iaebfef082eca0da8a305043fafb6d85e5de14cf8
2021-04-08 00:16:01 +00:00
Satya Tangirala
e13617100d Remove HardwareAuthToken support from vold::Keymaster
HardwareAuthTokens are no longer used by vold since Android P. So remove
the auth token parameter from vold. This patch doesn't remove the token
from IVold.aidl, and the methods in VoldNativeService.cpp return an
error if a non-empty auth token is passed to them.

Bug: 181910578
Test: cuttlefish and bramble boot with patch
Change-Id: I1a9f54e10f9efdda9973906afd0a5de5a699ada5
2021-04-07 02:05:35 -07:00
Eric Biggers
b2024e0349 KeyStorage: improve logging for key generation
The error messages that are printed when probing for rollback resistance
support on a device that doesn't support rollback-resistant keys can
make it sound like something is going wrong.  Print a WARNING message
afterwards to try to make it clear what is going on.  Also adjust or add
DEBUG messages when starting to generate each key so that it's easier to
distinguish the log messages for different key generation operations.

Bug: 182815123
Test: boot on device that doesn't support rollback-resistant keys and
      check log.
Change-Id: I37a13eb5c1e839fb94581f3e7ec1cd8da0263d2b
2021-03-15 12:44:36 -07:00
Eric Biggers
3345a2a98c Sync parent directory in storeKeyAtomically()
When an FBE or metadata encryption key is created, it's important that
it be persisted to disk right away; otherwise the device may fail to
boot after an unclean shutdown.  storeKey() has the needed fsync()s.
However, storeKeyAtomically() doesn't, as it doesn't fsync() the parent
directory of key_path after it renames tmp_path to it.

Two callers do fsync() the parent directory themselves, but others
don't.  E.g., the metadata encryption key doesn't get properly synced.

Therefore, add the needed fsync() to storeKeyAtomically() so that it
gets done for everyone.

Also remove the now-unneeded fsync()s from the two callers that did it
themselves.

Change-Id: I342ebd94f0a3d2bf3a7a443c35b6bda0f12e1ab2
2021-02-16 16:05:38 -08:00
Eric Biggers
bd138dd08a Move pathExists() to Utils.cpp
This is useful as a general utility function.

Change-Id: Id43fc106dc6c544c6e4ce65f10c7d4246b99e54a
2021-02-16 16:05:38 -08:00
Seth Moore
5a43d61e66 Add support for binding storage encryption to a seed
With this change, vold exposes an API that may be used to bind key
storage encryption keys to a given seed value. The seed value passed to
vold must be consistent across reboots, or key storage keys will not be
derived consistently. The seed is expected to be set very early in boot,
prior to the use of any key storage encryption keys.

This feature is intended to be used for embedded applications such as
in autos, where the seed may be provided by some other component of the
system. In such systems, there is a default user that is automatically
signed in without a PIN or other credentials. By binding the file
encryption to a platform-provided seed, the default user's data gains
additional protection against removal of the Android embedded device
from the integrated system.

Bug: 157501579
Test: Set seed at startup via init.rc. Seed changes fail as expected.
Change-Id: I9b048ec5e045b84c45883724ace2356d4ef6244d
2021-01-26 21:30:19 +00:00
Eric Biggers
f74373b177 KeyStorage: rework key upgrade handling
Remove the error-prone 'keepOld' parameter, and instead make begin()
(renamed to BeginKeymasterOp()) do all the key upgrade handling.

Don't handle /data and /metadata differently anymore.  Previously, when
a checkpoint is active, key blob files were replaced on /data
immediately; only the actual Keymaster key deletion was delayed until
checkpoint commit.  But it's easier to just delay the key blob file
replacement too, as we have to implement that for /metadata anyway.

Also be more vigilant about deleting any leftover upgraded keys.

Test: Tested on bramble using an OTA rvc-d1-release => master.  In OTA
      success case, verified via logcat that the keys were upgraded and
      then were committed after the boot succeeded.  In OTA failure
      case, verified that the device still boots -- i.e., the old keys
      weren't lost.  Verified that in either case, no
      keymaster_key_blob_upgraded files were left over.  Finally, also
      tried 'pm create-user' and 'pm remove-user' and verified via
      logcat that the Keymaster keys still get deleted.
Change-Id: Ic9c3e63e0bcae0c608fc79050ca4a1676b3852ee
2020-11-05 19:58:26 -08:00
Gaurav Kashyap
75736a8811 vold: Generate storage key without rollback resistance
Generate a storage key without rollback_resistance when device doesnt
support the corresponding tag.

Bug: 168527558

Change-Id: Iaf27c64dba627a31c9cbd9178458bf6785d00251
2020-10-20 16:19:33 +00:00
Paul Crowley
d281de75ad Fix unaligned access to auth token user_id
Bug: 65232288
Test: Set a pattern on cuttlefish, ensure we can unlock
Change-Id: I5ee09cf72ab7d3d636a25755134bfad6f88265f9
2020-02-18 11:00:15 -08:00
Barani Muthukumaran
3dfb094cb2 vold: Support Storage keys for FBE
To prevent keys from being compromised if an attacker
acquires read access to kernel memory, some inline
encryption hardware supports protecting the keys in
hardware without software having access to or the
ability to set the plaintext keys.  Instead, software
only sees "wrapped keys", which may differ on every boot.

'wrappedkey_v0' fileencryption flag is used to denote
that the device supports inline encryption hardware that
supports this feature. On such devices keymaster is used
to generate keys with STORAGE_KEY tag and export a
per-boot ephemerally wrapped storage key to install it in
the kernel.

The wrapped key framework in the linux kernel ensures the
wrapped key is provided to the inline encryption hardware
where it is unwrapped and the file contents key is derived
to encrypt contents without revealing the plaintext key in
the clear.

Test: FBE validation with Fscrypt v2 + inline crypt + wrapped
key changes kernel.

Bug: 147733587

Change-Id: I1f0de61b56534ec1df9baef075acb74bacd00758
2020-02-12 14:26:26 -08:00
Shawn Willden
35f0f22c9b Update vold to use KM4.1
This CL updates vold to use the Keymaster 4.1 interface, but does not
yet call any of the new methods.

Test: Boot the device
Change-Id: I4574a2f6eead3b71d1e89488b496b734694620c7
Merged-In: I4574a2f6eead3b71d1e89488b496b734694620c7
2020-02-11 15:51:04 -07:00
Treehugger Robot
aae52f4816 Merge "Request rollback resistance for FBE keys." 2019-09-12 15:20:45 +00:00
Daniel Rosenberg
d2906b8b5f Fix include order
Change-Id: Id839cc52801f3d0fce2d46faecf813812613e431
Test: None
2019-06-07 14:18:40 -07:00
Daniel Rosenberg
a48730a0fd Defer deleteKey in KeyStorage in Checkpointing mode
Don't delete keys in checkpointing mode. Instead wait until the
checkpoint has been committed.

Bug: 134631661
Test: Flash A with a working build. Flash B with a broken build. Test
      that the device rolls back to A without getting sent to recovery.
Merged-In: Ie5fc2d098355e2d095c53e9a95a6a8c7ab7ed051
Change-Id: Ie5fc2d098355e2d095c53e9a95a6a8c7ab7ed051
2019-06-07 14:11:01 -07:00
Tommy Chiu
97466cb145 vold: Introduce android::vold::writeStringToFile
Remove static definition of writeStringToFile, and
move it from KeyStorage to Utils

(cherry picked from commit 0bd2d11692)

Bug: 71810347
Test: Build pass and reboot stress test.
Change-Id: I38bfd27370ac2372e446dc699f518122e73c6877
Merged-In: I38bfd27370ac2372e446dc699f518122e73c6877
2019-04-05 04:06:18 -07:00
Woody Lin
37c82f5c0f Fsync directories before delete key
The boot failure symptom is reproduced on Walleye devices. System boots
up after taking OTA and try to upgrade key, but keymaster returns "failed
to ugprade key". Device reboots to recovery mode because of the failure,
and finally trapped in bootloader screen. Possible scenario is:

(After taking OTA)
vold sends old key and op=UPGRADE to keymaster
keymaster creates and saves new key to RPMB, responses new key to vold
vold saves new key as temp key
vold renames temp key to main key -------------- (1) -- still in cache
vold sends old key and op=DELETE_KEY to keymaster
keymaster removes old key from RPMB ------------ (2) -- write directly to RPMB
==> SYSTEM INTERRUPTED BY CRASH OR SOMETHING; ALL CACHE LOST.
==> System boots up, key in RPMB is deleted but key in storage is old key.

Solution: A Fsync is required between (1) and (2) to cover this case.

Detail analysis: b/124279741#comment21

Bug: 112145641
Bug: 124279741
Test: Insert fault right after deleteKey in vold::begin (KeyStorage.cpp),
      original boot failure symptom is NOT reproducible.
Change-Id: Ib8c349d6d033f86b247f4b35b8354d97cf249d26
2019-03-14 16:48:32 +08:00
Paul Crowley
621d9b9732 Fsync directories after creating files
Bug: 120248692
Test: adb shell locksettings set-pin 1111 && \
    adb shell "echo b > /proc/sysrq-trigger"
Change-Id: I53d252942c21365983b4f8b6e0948b1864f195c1
2019-01-07 04:30:08 -08:00
Daniel Rosenberg
690d6de5bf Add Support for metadata key with rollback
This adds the ability to upgrade a key and retain the
old one for rollback purposes. We delete the old key
if we boot successfully and delete the new key if we
do not.

Test: Enable checkpointing and test rolling back
      between two versions
Bug: 111020314

Change-Id: I19f31a1ac06a811c0644fc956e61b5ca84e7241a
2018-12-14 14:55:28 -08:00
Shawn Willden
8431fe24cb Request rollback resistance for FBE keys.
Test: Manual
Bug: 119663806
Change-Id: I954f2c7bfe65fbed88832432a89dacf3899498f2
2018-12-06 07:45:02 -07:00
Paul Crowley
14c8c0765a clang-format many files.
Test: Format-only changes; treehugger suffices.
Change-Id: I23cde3f0bbcac13bef555d13514e922c79d5ad48
2018-09-18 15:41:22 -07:00
Shawn Willden
353518194e Support Keymaster4
This CL changes vold from using a KM3 device directly to using the KM4
support wrapper from the KM4 support library, which supports both KM3
and KM4 devices (KM0, 1 and 2 devices are still supported as well,
because the default KM3 device is a wrapper that uses them).

In addition, I found myself getting confused about which "Keymaster"
types were locally-defined vold keymaster types and which were from
the KM4 HAL and support library, so I changd the approach to
referencing the latter, so all of them are qualified with the "km::"
namespace reference.

Test: Build & boot
Change-Id: I08ed5425641e7496f8597d5716cb3cd0cbd33a7f
2018-01-25 20:14:42 -07:00
Shawn Willden
785365b2f7 Clang-format Keymaster.{cpp|h} and KeyStorage.{cpp|h}
Test: Build & boot
Change-Id: I92bb107409f493770028cf6fd637d34af7644262
2018-01-25 20:09:46 -07:00
TreeHugger Robot
24224d10d0 Merge "Break vold dependency on keystore utilities." 2017-12-21 00:52:38 +00:00
Shawn Willden
f452774030 Break vold dependency on keystore utilities.
This is temporary.  Keystore is in the process of being upgraded to use
the new Keymaster 4.0 HAL, and I want to leave vold alone, using
Keymaster 3.0 for the moment.  This CL just copies relevant bits of
keystore support utilities into vold, so it can stop depending on the
copies from keystore.

After the keystore update is complete, vold will be changed either to
use Keymaster 4.0 or -- more likely -- to use keystore rather than
talking to Keymaster directly.  At that point the files added by this CL
will be deleted.

Test: Device boots and successfully decrypts /data
Change-Id: I73f6d4cc4c5e20d89d7ac37d29d025bf279f9e12
2017-11-09 16:05:38 -07:00
Wei Wang
a087947490 Vold: Add fsync in writeStringToFile() am: 701d05d32c
am: ee8170f2ac

Change-Id: I2ce9e9a6ea1969e1bf41ef6886dc4d27ee19f58a
2017-11-08 21:38:42 +00:00
Wei Wang
701d05d32c Vold: Add fsync in writeStringToFile()
Test: Build, test with ag/3180275
Bug: 68901441
Change-Id: Ieca9e5227025e00184a67508d5e8fbbddd12f21e
2017-11-08 19:01:33 +00:00
Paul Crowley
26a53888a4 When we forget a volume, forget per-volume key
Protect all per-volume-per-user keys with a per-volume key, which is
forgotten when the volume is forgotten. This means that the user's key
is securely lost even when their storage is encrypted at forgetting
time.

Bug: 25861755
Test: create a volume, forget it, check logs and filesystem.
Change-Id: I8df77bc91bbfa2258e082ddd54d6160dbf39b378
2017-10-26 12:19:09 -07:00
Paul Crowley
ff19b05e8e Fix errors on non-keymaster keys
If it's not a keymaster key, don't try to invalidate or delete the key
blob.

Bug: 25861755
Test: Create and forget a volume, check logs and files.
Change-Id: If8bfb1a9ab41e6c7e46bc311eb296242e56d264f
2017-10-26 11:38:14 -07:00
Pavel Grafov
e2e2d308df Zero memory used for encryuption keys.
std::vector with custom zeroing allocator is used instead of
std::string for data that can contain encryption keys.

Bug: 64201177
Test: manually created a managed profile, changed it's credentials
Test: manually upgraded a phone with profile from O to MR1.
Change-Id: Ic31877049f69eba9f8ea64fd99acaaca5a01d3dd
2017-08-10 17:31:03 +01:00
Rubin Xu
2436e27717 Add secdiscard command for secure deletion of files
This is used by LockSettingsService to delete sensitive credential files.

Bug: 34600579
Test: manual - change device lock under synthetic password, verify
      old data on disk is erased.

Change-Id: I5e11b559ad8818bd2ad2b321d67d21477aab7555
2017-05-16 12:44:02 +01:00
Paul Crowley
f71ace310e Refactor to lay the groundwork for metadata encryption
Bug: 26778031
Test: Angler, Marlin build and boot
Change-Id: Ic136dfe6195a650f7db76d3489f36da6a1929dc5
2017-04-21 10:47:17 -07:00
Wei Wang
4375f1be4c Change to use new WaitForProperty API
Change to use WaitForProperty API to wait for vold.post_fs_data_done
Also change cryptfs to C++

Bug: 35425974
Test: mma, marlin/angler boot

Change-Id: Id821f2035788fcc91909f296c83c871c67571de3
2017-02-24 17:47:53 -08:00
Paul Crowley
6ab2cabd19 Support keys with a secret but no token, which are handled not using
Keymaster but in-process crypto.

Bug: 33384925
Test: manual for now: patch KeyAuthentication.usesKeymaster() to always return true;
      flash a FBE device, add a device PIN, reboot and verify PIN can unlock FBE.
      Then clear device PIN, reboot and verify FBE is unlocked automatically.
      In both cases, check there is no keymaster_key_blob in
      /data/misc/vold/user_keys/ce/0/current/
      Unit tests to be added.
Change-Id: Ia94e2b39d60bfd98c7a8347a5ba043eeab6928c5
2017-02-13 23:37:31 +00:00
Janis Danisevskis
8e537b8002 Port to binder based keymaster hal
Bug: 32020919
Change-Id: If45ece76fdaf4d2c80eddc537e429633e4d42f9d
2017-01-17 11:23:40 +00:00
Paul Crowley
dff8c727c1 Support Keymaster 2 configuration and key upgrading
Bug: 27212248
Change-Id: I96bd9a442f4f535ba6ea44c9e81bcc1fee0ec471
2016-08-15 13:58:37 -07:00
Paul Crowley
beb33a67e1 Run secdiscard on encrypted key and key blob too
Don't rely on cryptographic binding of secdiscard to key; securely
delete the other information needed to reconstruct the key too.

Bug: 26021231
Change-Id: If03d2c051b0ec2fdcb5c6f70bde7e3287424f216
2016-07-11 17:31:44 -07:00
Paul Crowley
b3de337acd Use a longer timeout on the disk encryption keys
Avoid a timeout error by extending the time allowed between getting
the auth token and decrypting the key from five to thirty seconds.

Bug: 28398766
Change-Id: I1dbb9e0e33707e7de4c1720ad1b8e153c77094b2
2016-04-27 12:58:41 -07:00
Paul Crowley
df528a7011 Run clang-format over ext4crypt related code
The formatting here is inconsistent with Android house style; use
clang-format to bring it back into line.

Change-Id: Id1fe6ff54e9b668ca88c3fc021ae0a5bdd1327eb
2016-03-09 09:34:13 -08:00
Paul Crowley
a051eb7a22 Use pointers not references for out arguments
Google/Android C++ style requires that arguments passed in for writing
should be pointers, not references, so that it's visible in the caller
that they'll be written to.

Bug: 27566014
Change-Id: I5cd55906cc4b2f61c8b97b223786be0b3ce28862
2016-03-09 09:32:02 -08:00
Paul Crowley
320e5e15b6 Require the auth token for decryption.
A bug meant that the auth token wasn't being used; it turns out that
in order to use it we need to do things slightly differently.

Bug: 27496553
Change-Id: I0f0ab77fed31b92a79eba4acf488cb098691b4be
2016-03-08 14:32:00 -08:00
Paul Crowley
d9b9295b8c Fix memory leak in generate_key wrapper. Other fixes.
- catch errors in looking for the keyring
- static_assert to prevent a buffer overrun
- remove obsolete, misleading comment
- dial down priority of some log messages
- explain why we ignore some errors
- idiomatic C++11

Bug: 27552432
Change-Id: Ic3ee05b41eae45e7c6b571a459b326a483663526
2016-03-08 14:31:49 -08:00
Paul Crowley
63c18d3ba9 Add scrypt-based password stretching.
Bug: 27056334
Change-Id: Ifa7f776c21c439f89dad7836175fbd045e1c603e
2016-02-10 14:07:59 +00:00