From 5e49692058c62dc0eecbd09cca80720ad2976d0d Mon Sep 17 00:00:00 2001 From: Gil Date: Mon, 20 Nov 2017 20:53:08 -0800 Subject: Add SecureRandom (#473) * Add SecureRandom * Add CMake support for building src/support --- CMakeLists.txt | 2 + Firestore/CMakeLists.txt | 3 ++ .../Example/Firestore.xcodeproj/project.pbxproj | 14 +++++- Firestore/Firestore.podspec | 1 + Firestore/src/support/CMakeLists.txt | 18 +++++++ Firestore/src/support/port.h | 33 +++++++++++++ Firestore/src/support/secure_random.h | 55 ++++++++++++++++++++++ Firestore/src/support/secure_random_arc4random.cc | 33 +++++++++++++ Firestore/test/support/CMakeLists.txt | 22 +++++++++ Firestore/test/support/secure_random_test.cc | 32 +++++++++++++ cmake/utils.cmake | 29 ++++++++++++ 11 files changed, 241 insertions(+), 1 deletion(-) create mode 100644 Firestore/src/support/CMakeLists.txt create mode 100644 Firestore/src/support/port.h create mode 100644 Firestore/src/support/secure_random.h create mode 100644 Firestore/src/support/secure_random_arc4random.cc create mode 100644 Firestore/test/support/CMakeLists.txt create mode 100644 Firestore/test/support/secure_random_test.cc create mode 100644 cmake/utils.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 83950a9..53b454d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,5 +27,7 @@ include_directories("${PROJECT_SOURCE_DIR}") # check target that add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure) +include(cmake/utils.cmake) + enable_testing() add_subdirectory(Firestore) diff --git a/Firestore/CMakeLists.txt b/Firestore/CMakeLists.txt index 99f0ab1..4274056 100644 --- a/Firestore/CMakeLists.txt +++ b/Firestore/CMakeLists.txt @@ -13,3 +13,6 @@ # limitations under the License. include(${PROJECT_SOURCE_DIR}/cmake/external/googletest.cmake) + +add_subdirectory(src/support) +add_subdirectory(test/support) diff --git a/Firestore/Example/Firestore.xcodeproj/project.pbxproj b/Firestore/Example/Firestore.xcodeproj/project.pbxproj index 1cc4f83..62b73aa 100644 --- a/Firestore/Example/Firestore.xcodeproj/project.pbxproj +++ b/Firestore/Example/Firestore.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ /* Begin PBXBuildFile section */ 3B843E4C1F3A182900548890 /* remote_store_spec_test.json in Resources */ = {isa = PBXBuildFile; fileRef = 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */; }; + 5463926E1FBEDE28005031AA /* secure_random_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 5463926D1FBEDE28005031AA /* secure_random_test.cc */; }; 54764FAB1FAA0C320085E60A /* string_util_test.cc in Sources */ = {isa = PBXBuildFile; fileRef = 54764FAA1FAA0C320085E60A /* string_util_test.cc */; }; 54764FAF1FAA21B90085E60A /* FSTGoogleTestTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */; }; 5491BC721FB44593008B3588 /* FSTIntegrationTestCase.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */; }; @@ -183,6 +184,7 @@ 3B843E4A1F3930A400548890 /* remote_store_spec_test.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = remote_store_spec_test.json; sourceTree = ""; }; 42491D7DC8C8CD245CC22B93 /* Pods-SwiftBuildTest.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SwiftBuildTest.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SwiftBuildTest/Pods-SwiftBuildTest.debug.xcconfig"; sourceTree = ""; }; 4EBC5F5ABE1FD097EFE5E224 /* Pods-Firestore_Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Firestore_Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Firestore_Example/Pods-Firestore_Example.release.xcconfig"; sourceTree = ""; }; + 5463926D1FBEDE28005031AA /* secure_random_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = secure_random_test.cc; path = ../../test/support/secure_random_test.cc; sourceTree = ""; }; 54764FAA1FAA0C320085E60A /* string_util_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = string_util_test.cc; path = ../../Port/string_util_test.cc; sourceTree = ""; }; 54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = FSTGoogleTestTests.mm; path = GoogleTest/FSTGoogleTestTests.mm; sourceTree = ""; }; 5491BC711FB44593008B3588 /* FSTIntegrationTestCase.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = FSTIntegrationTestCase.mm; sourceTree = ""; }; @@ -364,11 +366,20 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 5463926F1FBEDE2F005031AA /* support */ = { + isa = PBXGroup; + children = ( + 5463926D1FBEDE28005031AA /* secure_random_test.cc */, + ); + name = support; + sourceTree = ""; + }; 54764FAC1FAA0C390085E60A /* GoogleTests */ = { isa = PBXGroup; children = ( - 54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */, 54764FAD1FAA0C650085E60A /* Port */, + 5463926F1FBEDE2F005031AA /* support */, + 54764FAE1FAA21B90085E60A /* FSTGoogleTestTests.mm */, ); name = GoogleTests; sourceTree = ""; @@ -1204,6 +1215,7 @@ DE51B1D91F0D490D0013853F /* FSTEagerGarbageCollectorTests.m in Sources */, DE51B1E21F0D490D0013853F /* FSTMutationQueueTests.m in Sources */, DE51B1E81F0D490D0013853F /* FSTLevelDBKeyTests.mm in Sources */, + 5463926E1FBEDE28005031AA /* secure_random_test.cc in Sources */, DE51B1E31F0D490D0013853F /* FSTPersistenceTestHelpers.m in Sources */, DE51B1CF1F0D48CD0013853F /* FSTQueryListenerTests.m in Sources */, DE51B1DA1F0D490D0013853F /* FSTLevelDBLocalStoreTests.m in Sources */, diff --git a/Firestore/Firestore.podspec b/Firestore/Firestore.podspec index 56683f1..d56b7a3 100644 --- a/Firestore/Firestore.podspec +++ b/Firestore/Firestore.podspec @@ -29,6 +29,7 @@ Google Cloud Firestore is a NoSQL document database built for automatic scaling, 'Port/**/*', 'Protos/objc/**/*.[hm]', 'src/core/**/*.{h,cc}', + 'src/support/**/*.{h,cc}', 'third_party/**/*.[mh]' ] s.requires_arc = [ diff --git a/Firestore/src/support/CMakeLists.txt b/Firestore/src/support/CMakeLists.txt new file mode 100644 index 0000000..8110c6f --- /dev/null +++ b/Firestore/src/support/CMakeLists.txt @@ -0,0 +1,18 @@ +# Copyright 2017 Google +# +# 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. + +add_library( + firestore_support + secure_random_arc4random.cc +) diff --git a/Firestore/src/support/port.h b/Firestore/src/support/port.h new file mode 100644 index 0000000..6af898a --- /dev/null +++ b/Firestore/src/support/port.h @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Google + * + * 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 FIRESTORE_SRC_SUPPORT_PORT_H_ +#define FIRESTORE_SRC_SUPPORT_PORT_H_ + +#if defined(__APPLE__) +// On Apple platforms we support building via Cocoapods without CMake. When +// building this way we can't test the presence of features so predefine all +// the platform-support feature macros to their expected values. + +// All supported Apple platforms have arc4random(3). +#define HAVE_ARC4RANDOM 1 + +#else + +#error "Unknown platform." +#endif // defined(__APPLE__) + +#endif // FIRESTORE_SRC_SUPPORT_PORT_H_ diff --git a/Firestore/src/support/secure_random.h b/Firestore/src/support/secure_random.h new file mode 100644 index 0000000..92a3eaf --- /dev/null +++ b/Firestore/src/support/secure_random.h @@ -0,0 +1,55 @@ +/* + * Copyright 2017 Google + * + * 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 FIRESTORE_SRC_SUPPORT_SECURE_RANDOM_H_ +#define FIRESTORE_SRC_SUPPORT_SECURE_RANDOM_H_ + +#include + +#include + +namespace firestore { + +// A "secure" pseudorandom number generator, suitable for generating +// unguessable identifiers. This exists because +// +// * std::mt19937 is blazing fast but its outputs can be guessed once enough +// previous outputs have been observed. +// * std::random_device isn't guaranteed to come from a secure PRNG or be +// fast. +// +// The implementation satisfies the C++11 UniformRandomBitGenerator concept and +// delegates to an implementation that generates high quality random values +// quickly with periodic reseeding. +class SecureRandom { + public: + // C++11 UniformRandomBitGenerator interface + using result_type = uint32_t; + + static constexpr result_type min() { + return std::numeric_limits::min(); + } + + static constexpr result_type max() { + return std::numeric_limits::max(); + } + + result_type operator()(); +}; + +} // namespace firestore + +#endif // FIRESTORE_SRC_SUPPORT_SECURE_RANDOM_H_ diff --git a/Firestore/src/support/secure_random_arc4random.cc b/Firestore/src/support/secure_random_arc4random.cc new file mode 100644 index 0000000..4cd7f9d --- /dev/null +++ b/Firestore/src/support/secure_random_arc4random.cc @@ -0,0 +1,33 @@ +/* + * Copyright 2017 Google + * + * 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 "Firestore/src/support/secure_random.h" + +#include "Firestore/src/support/port.h" + +#if HAVE_ARC4RANDOM + +#include + +namespace firestore { + +SecureRandom::result_type SecureRandom::operator()() { + return arc4random(); +} + +} // namespace firestore + +#endif // HAVE_ARC4RANDOM diff --git a/Firestore/test/support/CMakeLists.txt b/Firestore/test/support/CMakeLists.txt new file mode 100644 index 0000000..7de5367 --- /dev/null +++ b/Firestore/test/support/CMakeLists.txt @@ -0,0 +1,22 @@ +# Copyright 2017 Google +# +# 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. + +cc_test( + firestore_support_test + secure_random_test.cc +) +target_link_libraries( + firestore_support_test + firestore_support +) diff --git a/Firestore/test/support/secure_random_test.cc b/Firestore/test/support/secure_random_test.cc new file mode 100644 index 0000000..244227b --- /dev/null +++ b/Firestore/test/support/secure_random_test.cc @@ -0,0 +1,32 @@ +/* + * Copyright 2017 Google + * + * 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 "Firestore/src/support/secure_random.h" + +#include "gtest/gtest.h" + +using firestore::SecureRandom; + +TEST(SecureRandomTest, ResultsAreBounded) { + SecureRandom rng; + + // Verify that values are on the min/max closed interval. + for (int i = 0; i < 1000; i++) { + SecureRandom::result_type value = rng(); + EXPECT_GE(value, rng.min()); + EXPECT_LE(value, rng.max()); + } +} diff --git a/cmake/utils.cmake b/cmake/utils.cmake new file mode 100644 index 0000000..40e2325 --- /dev/null +++ b/cmake/utils.cmake @@ -0,0 +1,29 @@ +# Copyright 2017 Google +# +# 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. + +# Defines a new test executable and does all the things we want done with +# tests: +# +# * add_executable (with the given arguments) +# * add_Test - defines a test with the same name +# * declares that the test links against gtest +# * adds the executable as a dependency of the `check` target. +function(cc_test name) + add_executable(${name} ${ARGN}) + add_test(${name} ${name}) + + target_link_libraries(${name} gtest gtest_main) + + add_dependencies(check ${name}) +endfunction() -- cgit v1.2.3