libcouchbase 1.2.8 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -4
  3. data/README.md +16 -8
  4. data/ext/libcouchbase/CMakeLists.txt +34 -32
  5. data/ext/libcouchbase/RELEASE_NOTES.markdown +277 -6
  6. data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +14 -0
  7. data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibevent.cmake +2 -0
  8. data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibuv.cmake +2 -1
  9. data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
  10. data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +8 -1
  11. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
  12. data/ext/libcouchbase/cmake/config-cmake.h.in +14 -0
  13. data/ext/libcouchbase/cmake/configure +8 -26
  14. data/ext/libcouchbase/cmake/defs.mk.in +2 -2
  15. data/ext/libcouchbase/cmake/libcouchbase.stp.in +829 -0
  16. data/ext/libcouchbase/cmake/source_files.cmake +11 -2
  17. data/ext/libcouchbase/contrib/cbsasl/CMakeLists.txt +18 -2
  18. data/ext/libcouchbase/contrib/cbsasl/include/cbsasl/cbsasl.h +44 -2
  19. data/ext/libcouchbase/contrib/cbsasl/src/client.c +285 -73
  20. data/ext/libcouchbase/contrib/cbsasl/src/common.c +4 -0
  21. data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.c +500 -0
  22. data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.h +99 -0
  23. data/ext/libcouchbase/contrib/cliopts/CMakeLists.txt +1 -1
  24. data/ext/libcouchbase/contrib/cliopts/cliopts.h +14 -1
  25. data/ext/libcouchbase/contrib/snappy/CMakeLists.txt +2 -3
  26. data/ext/libcouchbase/contrib/snappy/snappy-sinksource.cc +4 -0
  27. data/ext/libcouchbase/contrib/snappy/snappy-stubs-public.h +7 -5
  28. data/ext/libcouchbase/contrib/snappy/snappy.cc +7 -2
  29. data/ext/libcouchbase/example/crypto/.gitignore +2 -0
  30. data/ext/libcouchbase/example/crypto/Makefile +13 -0
  31. data/ext/libcouchbase/example/crypto/common_provider.c +24 -0
  32. data/ext/libcouchbase/example/crypto/common_provider.h +31 -0
  33. data/ext/libcouchbase/example/crypto/openssl_symmetric_decrypt.c +139 -0
  34. data/ext/libcouchbase/example/crypto/openssl_symmetric_encrypt.c +147 -0
  35. data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.c +281 -0
  36. data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.h +29 -0
  37. data/ext/libcouchbase/example/tracing/.gitignore +2 -0
  38. data/ext/libcouchbase/example/tracing/Makefile +8 -0
  39. data/ext/libcouchbase/example/tracing/cJSON.c +1 -0
  40. data/ext/libcouchbase/example/tracing/cJSON.h +1 -0
  41. data/ext/libcouchbase/example/tracing/tracing.c +439 -0
  42. data/ext/libcouchbase/example/tracing/views.c +444 -0
  43. data/ext/libcouchbase/include/libcouchbase/auth.h +56 -4
  44. data/ext/libcouchbase/include/libcouchbase/cbft.h +8 -0
  45. data/ext/libcouchbase/include/libcouchbase/cntl-private.h +55 -1
  46. data/ext/libcouchbase/include/libcouchbase/cntl.h +101 -1
  47. data/ext/libcouchbase/include/libcouchbase/configuration.h.in +6 -0
  48. data/ext/libcouchbase/include/libcouchbase/couchbase.h +109 -6
  49. data/ext/libcouchbase/include/libcouchbase/crypto.h +140 -0
  50. data/ext/libcouchbase/include/libcouchbase/error.h +38 -2
  51. data/ext/libcouchbase/include/libcouchbase/kvbuf.h +6 -1
  52. data/ext/libcouchbase/include/libcouchbase/metrics.h +79 -0
  53. data/ext/libcouchbase/include/libcouchbase/n1ql.h +9 -0
  54. data/ext/libcouchbase/include/libcouchbase/tracing.h +319 -0
  55. data/ext/libcouchbase/include/libcouchbase/vbucket.h +1 -1
  56. data/ext/libcouchbase/include/libcouchbase/views.h +8 -0
  57. data/ext/libcouchbase/include/memcached/protocol_binary.h +40 -10
  58. data/ext/libcouchbase/packaging/rpm/libcouchbase.spec.in +6 -14
  59. data/ext/libcouchbase/plugins/io/libuv/plugin-internal.h +3 -0
  60. data/ext/libcouchbase/plugins/io/libuv/plugin-libuv.c +1 -0
  61. data/ext/libcouchbase/plugins/io/select/plugin-select.c +4 -1
  62. data/ext/libcouchbase/src/auth-priv.h +36 -4
  63. data/ext/libcouchbase/src/auth.cc +66 -27
  64. data/ext/libcouchbase/src/bootstrap.cc +1 -1
  65. data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +12 -7
  66. data/ext/libcouchbase/src/bucketconfig/bc_http.cc +26 -17
  67. data/ext/libcouchbase/src/bucketconfig/bc_http.h +1 -1
  68. data/ext/libcouchbase/src/bucketconfig/clconfig.h +4 -2
  69. data/ext/libcouchbase/src/bucketconfig/confmon.cc +6 -3
  70. data/ext/libcouchbase/src/cbft.cc +48 -0
  71. data/ext/libcouchbase/src/cntl.cc +138 -2
  72. data/ext/libcouchbase/src/config_static.h +17 -0
  73. data/ext/libcouchbase/src/connspec.cc +54 -6
  74. data/ext/libcouchbase/src/connspec.h +9 -1
  75. data/ext/libcouchbase/src/crypto.cc +386 -0
  76. data/ext/libcouchbase/src/ctx-log-inl.h +23 -6
  77. data/ext/libcouchbase/src/dump.cc +4 -0
  78. data/ext/libcouchbase/src/getconfig.cc +1 -2
  79. data/ext/libcouchbase/src/handler.cc +65 -27
  80. data/ext/libcouchbase/src/hostlist.cc +35 -7
  81. data/ext/libcouchbase/src/hostlist.h +7 -0
  82. data/ext/libcouchbase/src/http/http-priv.h +2 -0
  83. data/ext/libcouchbase/src/http/http.cc +77 -37
  84. data/ext/libcouchbase/src/http/http_io.cc +19 -2
  85. data/ext/libcouchbase/src/instance.cc +90 -17
  86. data/ext/libcouchbase/src/internal.h +5 -0
  87. data/ext/libcouchbase/src/lcbio/connect.cc +39 -4
  88. data/ext/libcouchbase/src/lcbio/connect.h +27 -0
  89. data/ext/libcouchbase/src/lcbio/ctx.c +49 -23
  90. data/ext/libcouchbase/src/lcbio/ioutils.cc +30 -3
  91. data/ext/libcouchbase/src/lcbio/ioutils.h +2 -0
  92. data/ext/libcouchbase/src/lcbio/manager.cc +44 -8
  93. data/ext/libcouchbase/src/lcbio/manager.h +2 -0
  94. data/ext/libcouchbase/src/lcbio/rw-inl.h +1 -0
  95. data/ext/libcouchbase/src/lcbio/ssl.h +3 -5
  96. data/ext/libcouchbase/src/logging.c +1 -1
  97. data/ext/libcouchbase/src/logging.h +2 -0
  98. data/ext/libcouchbase/src/mc/compress.cc +164 -0
  99. data/ext/libcouchbase/src/mc/compress.h +7 -12
  100. data/ext/libcouchbase/src/mc/mcreq-flush-inl.h +5 -1
  101. data/ext/libcouchbase/src/mc/mcreq.c +11 -1
  102. data/ext/libcouchbase/src/mc/mcreq.h +35 -4
  103. data/ext/libcouchbase/src/mcserver/mcserver.cc +30 -7
  104. data/ext/libcouchbase/src/mcserver/mcserver.h +7 -0
  105. data/ext/libcouchbase/src/mcserver/negotiate.cc +103 -57
  106. data/ext/libcouchbase/src/mcserver/negotiate.h +2 -2
  107. data/ext/libcouchbase/src/mctx-helper.h +11 -0
  108. data/ext/libcouchbase/src/metrics.cc +132 -0
  109. data/ext/libcouchbase/src/n1ql/ixmgmt.cc +2 -1
  110. data/ext/libcouchbase/src/n1ql/n1ql.cc +66 -0
  111. data/ext/libcouchbase/src/newconfig.cc +9 -2
  112. data/ext/libcouchbase/src/operations/counter.cc +2 -1
  113. data/ext/libcouchbase/src/operations/durability-cas.cc +11 -0
  114. data/ext/libcouchbase/src/operations/durability-seqno.cc +3 -0
  115. data/ext/libcouchbase/src/operations/durability.cc +24 -2
  116. data/ext/libcouchbase/src/operations/durability_internal.h +19 -0
  117. data/ext/libcouchbase/src/operations/get.cc +4 -2
  118. data/ext/libcouchbase/src/operations/observe-seqno.cc +1 -0
  119. data/ext/libcouchbase/src/operations/observe.cc +113 -62
  120. data/ext/libcouchbase/src/operations/ping.cc +246 -67
  121. data/ext/libcouchbase/src/operations/remove.cc +2 -1
  122. data/ext/libcouchbase/src/operations/store.cc +17 -14
  123. data/ext/libcouchbase/src/operations/touch.cc +3 -0
  124. data/ext/libcouchbase/src/packetutils.h +68 -4
  125. data/ext/libcouchbase/src/probes.d +132 -161
  126. data/ext/libcouchbase/src/rdb/bigalloc.c +1 -1
  127. data/ext/libcouchbase/src/retryq.cc +6 -2
  128. data/ext/libcouchbase/src/rnd.cc +68 -0
  129. data/ext/libcouchbase/src/rnd.h +39 -0
  130. data/ext/libcouchbase/src/settings.c +27 -0
  131. data/ext/libcouchbase/src/settings.h +67 -3
  132. data/ext/libcouchbase/src/ssl/CMakeLists.txt +0 -12
  133. data/ext/libcouchbase/src/ssl/ssl_common.c +23 -4
  134. data/ext/libcouchbase/src/strcodecs/base64.c +141 -16
  135. data/ext/libcouchbase/src/strcodecs/strcodecs.h +16 -1
  136. data/ext/libcouchbase/src/trace.h +68 -61
  137. data/ext/libcouchbase/src/tracing/span.cc +289 -0
  138. data/ext/libcouchbase/src/tracing/threshold_logging_tracer.cc +171 -0
  139. data/ext/libcouchbase/src/tracing/tracer.cc +53 -0
  140. data/ext/libcouchbase/src/tracing/tracing-internal.h +213 -0
  141. data/ext/libcouchbase/src/utilities.c +5 -0
  142. data/ext/libcouchbase/src/vbucket/CMakeLists.txt +2 -2
  143. data/ext/libcouchbase/src/vbucket/vbucket.c +50 -18
  144. data/ext/libcouchbase/src/views/docreq.cc +26 -1
  145. data/ext/libcouchbase/src/views/docreq.h +17 -0
  146. data/ext/libcouchbase/src/views/viewreq.cc +64 -1
  147. data/ext/libcouchbase/src/views/viewreq.h +21 -0
  148. data/ext/libcouchbase/tests/CMakeLists.txt +6 -6
  149. data/ext/libcouchbase/tests/basic/t_base64.cc +34 -6
  150. data/ext/libcouchbase/tests/basic/t_connstr.cc +14 -0
  151. data/ext/libcouchbase/tests/basic/t_creds.cc +10 -10
  152. data/ext/libcouchbase/tests/basic/t_host.cc +22 -2
  153. data/ext/libcouchbase/tests/basic/t_scram.cc +514 -0
  154. data/ext/libcouchbase/tests/check-all.cc +6 -2
  155. data/ext/libcouchbase/tests/iotests/mock-environment.cc +64 -0
  156. data/ext/libcouchbase/tests/iotests/mock-environment.h +27 -1
  157. data/ext/libcouchbase/tests/iotests/t_confmon.cc +2 -2
  158. data/ext/libcouchbase/tests/iotests/t_forward.cc +8 -0
  159. data/ext/libcouchbase/tests/iotests/t_netfail.cc +124 -0
  160. data/ext/libcouchbase/tests/iotests/t_smoke.cc +1 -1
  161. data/ext/libcouchbase/tests/iotests/t_snappy.cc +316 -0
  162. data/ext/libcouchbase/tests/socktests/socktest.cc +2 -2
  163. data/ext/libcouchbase/tests/socktests/t_basic.cc +6 -6
  164. data/ext/libcouchbase/tests/socktests/t_manager.cc +1 -1
  165. data/ext/libcouchbase/tests/socktests/t_ssl.cc +1 -1
  166. data/ext/libcouchbase/tools/CMakeLists.txt +1 -1
  167. data/ext/libcouchbase/tools/cbc-handlers.h +17 -0
  168. data/ext/libcouchbase/tools/cbc-n1qlback.cc +7 -4
  169. data/ext/libcouchbase/tools/cbc-pillowfight.cc +408 -100
  170. data/ext/libcouchbase/tools/cbc-proxy.cc +134 -3
  171. data/ext/libcouchbase/tools/cbc-subdoc.cc +1 -2
  172. data/ext/libcouchbase/tools/cbc.cc +113 -8
  173. data/ext/libcouchbase/tools/common/histogram.cc +1 -0
  174. data/ext/libcouchbase/tools/common/options.cc +28 -1
  175. data/ext/libcouchbase/tools/common/options.h +5 -0
  176. data/ext/libcouchbase/tools/docgen/docgen.h +36 -10
  177. data/ext/libcouchbase/tools/docgen/loc.h +5 -4
  178. data/ext/libcouchbase/tools/docgen/seqgen.h +28 -0
  179. data/lib/libcouchbase/ext/libcouchbase/enums.rb +10 -0
  180. data/lib/libcouchbase/n1ql.rb +6 -1
  181. data/lib/libcouchbase/version.rb +1 -1
  182. data/spec/connection_spec.rb +6 -6
  183. metadata +38 -5
  184. data/ext/libcouchbase/cmake/Modules/FindCouchbaseSnappy.cmake +0 -11
  185. data/ext/libcouchbase/src/mc/compress.c +0 -90
  186. data/ext/libcouchbase/tools/common/my_inttypes.h +0 -22
@@ -189,6 +189,20 @@ TEST_F(ConnstrTest, testParseHosts)
189
189
  ASSERT_FALSE(NULL == findHost(&params, "foo.com"));
190
190
  ASSERT_FALSE(NULL == findHost(&params, "bar.com"));
191
191
  ASSERT_FALSE(NULL == findHost(&params, "baz.com"));
192
+
193
+ reinit();
194
+ err = params.parse("couchbase://"
195
+ "::a15:f2df:3fef:51bb:212a:8cec,[::a15:f2df:3fef:51bb:212a:8ced],[::a15:f2df:3fef:51bb:212a:"
196
+ "8cee]:9001",
197
+ &errmsg);
198
+ ASSERT_EQ(LCB_SUCCESS, err) << "Cannot parse IPv6";
199
+ ASSERT_EQ(3, countHosts(&params));
200
+ ASSERT_FALSE(NULL == findHost(&params, "::a15:f2df:3fef:51bb:212a:8cec"));
201
+ ASSERT_FALSE(NULL == findHost(&params, "::a15:f2df:3fef:51bb:212a:8ced"));
202
+ dh = findHost(&params, "::a15:f2df:3fef:51bb:212a:8cee");
203
+ ASSERT_FALSE(dh == NULL);
204
+ ASSERT_EQ("::a15:f2df:3fef:51bb:212a:8cee", dh->hostname);
205
+ ASSERT_EQ(9001, dh->port);
192
206
  }
193
207
 
194
208
  TEST_F(ConnstrTest, testParseBucket)
@@ -30,16 +30,16 @@ TEST_F(CredsTest, testLegacyCreds)
30
30
 
31
31
  ASSERT_EQ(1, auth.buckets().size());
32
32
  ASSERT_TRUE(auth.buckets().find("default")->second.empty());
33
- ASSERT_EQ("", auth.password_for("default"));
34
- ASSERT_EQ("default", auth.username_for("default"));
33
+ ASSERT_EQ("", auth.password_for(NULL, NULL, "default"));
34
+ ASSERT_EQ("default", auth.username_for(NULL, NULL, "default"));
35
35
 
36
36
  // Try to add another user/password:
37
37
  lcb_BUCKETCRED creds = { "user2", "pass2" };
38
38
  ASSERT_EQ(LCB_SUCCESS, lcb_cntl(instance, LCB_CNTL_SET, LCB_CNTL_BUCKET_CRED, creds));
39
39
  ASSERT_EQ(2, auth.buckets().size());
40
40
  ASSERT_EQ("pass2", auth.buckets().find("user2")->second);
41
- ASSERT_EQ("user2", auth.username_for("user2"));
42
- ASSERT_EQ("pass2", auth.password_for("user2"));
41
+ ASSERT_EQ("user2", auth.username_for(NULL, NULL, "user2"));
42
+ ASSERT_EQ("pass2", auth.password_for(NULL, NULL, "user2"));
43
43
 
44
44
  ASSERT_TRUE(auth.username().empty());
45
45
  ASSERT_TRUE(auth.password().empty());
@@ -52,10 +52,10 @@ TEST_F(CredsTest, testRbacCreds) {
52
52
  ASSERT_EQ("mark", auth.username());
53
53
  ASSERT_EQ(LCBAUTH_MODE_RBAC, auth.mode());
54
54
  ASSERT_TRUE(auth.buckets().empty());
55
- ASSERT_EQ("mark", auth.username_for("default"));
56
- ASSERT_EQ("", auth.password_for("default"));
57
- ASSERT_EQ("mark", auth.username_for("jane"));
58
- ASSERT_EQ("", auth.password_for("jane"));
55
+ ASSERT_EQ("mark", auth.username_for(NULL, NULL, "default"));
56
+ ASSERT_EQ("", auth.password_for(NULL, NULL, "default"));
57
+ ASSERT_EQ("mark", auth.username_for(NULL, NULL, "jane"));
58
+ ASSERT_EQ("", auth.password_for(NULL, NULL, "jane"));
59
59
 
60
60
  // Try adding a new bucket, it should fail
61
61
  ASSERT_EQ(LCB_OPTIONS_CONFLICT, auth.add("users", "secret", LCBAUTH_F_BUCKET));
@@ -68,8 +68,8 @@ TEST_F(CredsTest, testRbacCreds) {
68
68
 
69
69
  // Try *changing* the credentials
70
70
  ASSERT_EQ(LCB_SUCCESS, auth.add("jane", "seekrit", LCBAUTH_F_CLUSTER));
71
- ASSERT_EQ("jane", auth.username_for("default"));
72
- ASSERT_EQ("seekrit", auth.password_for("default"));
71
+ ASSERT_EQ("jane", auth.username_for(NULL, NULL, "default"));
72
+ ASSERT_EQ("seekrit", auth.password_for(NULL, NULL, "default"));
73
73
  lcb_destroy(instance);
74
74
  }
75
75
 
@@ -30,7 +30,7 @@ static bool hostEquals(const lcb_host_t &host, const char *addr, const char *por
30
30
 
31
31
  TEST_F(Hostlist, testParseBasic)
32
32
  {
33
- lcb_host_t curhost;
33
+ lcb_host_t curhost = {0};
34
34
  lcb_error_t err;
35
35
 
36
36
  err = lcb_host_parsez(&curhost, "1.2.3.4", 8091);
@@ -59,12 +59,24 @@ TEST_F(Hostlist, testParseBasic)
59
59
 
60
60
  err = lcb_host_parsez(&curhost, "localhost:1111111111111111111111111111", 100);
61
61
  ASSERT_EQ(LCB_INVALID_HOST_FORMAT, err);
62
+
63
+ err = lcb_host_parsez(&curhost, "[::a15:f2df:4854:9ac6:8ceb:30a5]:9000", 8091);
64
+ ASSERT_EQ(LCB_SUCCESS, err);
65
+ ASSERT_TRUE(hostEquals(curhost, "::a15:f2df:4854:9ac6:8ceb:30a5", "9000"));
66
+
67
+ err = lcb_host_parsez(&curhost, "::a15:f2df:4854:9ac6:8ceb:30a5", 8091);
68
+ ASSERT_EQ(LCB_SUCCESS, err);
69
+ ASSERT_TRUE(hostEquals(curhost, "::a15:f2df:4854:9ac6:8ceb:30a5", "8091"));
70
+
71
+ err = lcb_host_parsez(&curhost, "::1", 8091);
72
+ ASSERT_EQ(LCB_SUCCESS, err);
73
+ ASSERT_TRUE(hostEquals(curhost, "::1", "8091"));
62
74
  }
63
75
 
64
76
 
65
77
  TEST_F(Hostlist, testEquals)
66
78
  {
67
- lcb_host_t host_a, host_b;
79
+ lcb_host_t host_a = {0}, host_b = {0};
68
80
  strcpy(host_a.host, "foo.com");
69
81
  strcpy(host_a.port, "1234");
70
82
  strcpy(host_b.host, "foo.com");
@@ -149,6 +161,14 @@ TEST_F(Hostlist, testParseList)
149
161
  hosts.randomize();
150
162
  hosts.clear();
151
163
  hosts.randomize();
164
+
165
+ hosts.clear();
166
+ err = hosts.add("fe80::dc59:5260:117d:33ec;[::a15:f2df:4854:9ac6:8ceb:30a5]:9000;::1:9000", 8091);
167
+ ASSERT_EQ(LCB_SUCCESS, err);
168
+ ASSERT_EQ(3, hosts.size());
169
+ ASSERT_TRUE(hosts.exists("[fe80::dc59:5260:117d:33ec]:8091"));
170
+ ASSERT_TRUE(hosts.exists("[::a15:f2df:4854:9ac6:8ceb:30a5]:9000"));
171
+ ASSERT_TRUE(hosts.exists("[::1:9000]:8091"));
152
172
  }
153
173
 
154
174
  TEST_F(Hostlist, testCycle)
@@ -0,0 +1,514 @@
1
+ /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
+ /*
3
+ * Copyright 2018 Couchbase, Inc.
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */
17
+ #include "config.h"
18
+ #include <gtest/gtest.h>
19
+
20
+ #include "contrib/cbsasl/src/scram-sha/scram_utils.h"
21
+
22
+ class ScramTest : public ::testing::Test
23
+ {
24
+ };
25
+
26
+ /**
27
+ * Tests the parse_server_challenge function.
28
+ */
29
+ TEST_F(ScramTest, ParseValidServerChallenge)
30
+ {
31
+ const char *serverin = "r=CCCCSSSS,s=xxxx,i=4096";
32
+ const char *nonce = NULL;
33
+ unsigned int noncelength = 0;
34
+ const char *salt = NULL;
35
+ unsigned int saltlength = 0;
36
+ unsigned int itcount = 0;
37
+
38
+ cbsasl_error_t ret =
39
+ parse_server_challenge(serverin, strlen(serverin), &nonce, &noncelength, &salt, &saltlength, &itcount);
40
+
41
+ ASSERT_EQ(SASL_OK, ret);
42
+ EXPECT_EQ(8, noncelength);
43
+ EXPECT_EQ("CCCCSSSS", std::string(nonce, noncelength));
44
+ EXPECT_EQ(4, saltlength);
45
+ EXPECT_EQ("xxxx", std::string(salt, saltlength));
46
+ EXPECT_EQ(4096, itcount);
47
+ }
48
+
49
+ TEST_F(ScramTest, ParseInvalidServerChallenge_WithWrongAttribute)
50
+ {
51
+ const char *serverin = "r=CCCCSSSS,t=xxxx,i=4096"; // 't' is not a valid attribute
52
+ const char *nonce = NULL;
53
+ unsigned int noncelength = 0;
54
+ const char *salt = NULL;
55
+ unsigned int saltlength = 0;
56
+ unsigned int itcount = 0;
57
+
58
+ cbsasl_error_t ret =
59
+ parse_server_challenge(serverin, strlen(serverin), &nonce, &noncelength, &salt, &saltlength, &itcount);
60
+
61
+ ASSERT_EQ(SASL_BADPARAM, ret);
62
+ }
63
+
64
+ TEST_F(ScramTest, ParseInvalidServerChallenge_WithMissingAttributeType)
65
+ {
66
+ const char *serverin = "r=CCCCSSSS,xxxx,i=4096"; // no "s="
67
+ const char *nonce = NULL;
68
+ unsigned int noncelength = 0;
69
+ const char *salt = NULL;
70
+ unsigned int saltlength = 0;
71
+ unsigned int itcount = 0;
72
+
73
+ cbsasl_error_t ret =
74
+ parse_server_challenge(serverin, strlen(serverin), &nonce, &noncelength, &salt, &saltlength, &itcount);
75
+
76
+ ASSERT_EQ(SASL_BADPARAM, ret);
77
+ }
78
+
79
+ TEST_F(ScramTest, ParseInvalidServerChallenge_WithVoidField)
80
+ {
81
+ const char *serverin = ",s=xxxx,i=4096";
82
+ const char *nonce = NULL;
83
+ unsigned int noncelength = 0;
84
+ const char *salt = NULL;
85
+ unsigned int saltlength = 0;
86
+ unsigned int itcount = 0;
87
+
88
+ cbsasl_error_t ret =
89
+ parse_server_challenge(serverin, strlen(serverin), &nonce, &noncelength, &salt, &saltlength, &itcount);
90
+
91
+ ASSERT_EQ(SASL_BADPARAM, ret);
92
+ }
93
+
94
+ TEST_F(ScramTest, ParseInvalidServerChallenge_WithInvalidIterationCount)
95
+ {
96
+ const char *serverin = "r=CCCCSSSS,s=xxxx,i=123456789012345"; // value too big for an integer
97
+ const char *nonce = NULL;
98
+ unsigned int noncelength = 0;
99
+ const char *salt = NULL;
100
+ unsigned int saltlength = 0;
101
+ unsigned int itcount = 0;
102
+
103
+ cbsasl_error_t ret =
104
+ parse_server_challenge(serverin, strlen(serverin), &nonce, &noncelength, &salt, &saltlength, &itcount);
105
+
106
+ ASSERT_EQ(SASL_BADPARAM, ret);
107
+ }
108
+
109
+ TEST_F(ScramTest, ParseInvalidServerChallenge_WithDuplicateAttribute)
110
+ {
111
+ const char *serverin = "r=CCCCSSSS,r=CCCCSSSS,s=xxxx,i=4096"; // "r" field appearing twice
112
+ const char *nonce = NULL;
113
+ unsigned int noncelength = 0;
114
+ const char *salt = NULL;
115
+ unsigned int saltlength = 0;
116
+ unsigned int itcount = 0;
117
+
118
+ cbsasl_error_t ret =
119
+ parse_server_challenge(serverin, strlen(serverin), &nonce, &noncelength, &salt, &saltlength, &itcount);
120
+
121
+ ASSERT_EQ(SASL_BADPARAM, ret);
122
+ }
123
+
124
+ // the following tests are valid only if OpenSSL is linked to the library
125
+ #ifndef LCB_NO_SSL
126
+ TEST_F(ScramTest, GenerateSaltedPasswordWithSHA512)
127
+ {
128
+ // here we check that the generate_salted_password function returns the expected output
129
+ // for a predefined password/salt/iteration count combination
130
+ union {
131
+ cbsasl_secret_t secret;
132
+ char buffer[30];
133
+ } u_auth;
134
+ unsigned char outbuffer[CBSASL_SHA512_DIGEST_SIZE];
135
+ unsigned int outlen;
136
+ const char *salt = "c2FsdA=="; // "salt" in base64
137
+ memcpy(u_auth.secret.data, "password", 8);
138
+ u_auth.secret.len = 8; // strlen("password")
139
+ // expected output was generated using the following Python algorithm:
140
+ // import hashlib, binascii
141
+ // dk = hashlib.pbkdf2_hmac('sha512', b'password', b'salt', 1000)
142
+ // print binascii.hexlify(dk)
143
+ const char *expectedoutput = "\xaf\xe6\xc5\x53\x07\x85\xb6\xcc\x6b\x1c\x64\x53\x38\x47\x31"
144
+ "\xbd\x5e\xe4\x32\xee\x54\x9f\xd4\x2f\xb6\x69\x57\x79\xad\x8a"
145
+ "\x1c\x5b\xf5\x9d\xe6\x9c\x48\xf7\x74\xef\xc4\x00\x7d\x52\x98"
146
+ "\xf9\x03\x3c\x02\x41\xd5\xab\x69\x30\x5e\x7b\x64\xec\xee\xb8"
147
+ "\xd8\x34\xcf\xec";
148
+ // warning: the expected output contains a binary zero, so don't use strlen()
149
+
150
+ cbsasl_error_t ret = generate_salted_password(SASL_AUTH_MECH_SCRAM_SHA512, &u_auth.secret, salt, strlen(salt), 1000,
151
+ outbuffer, &outlen);
152
+ ASSERT_EQ(SASL_OK, ret);
153
+ EXPECT_EQ(CBSASL_SHA512_DIGEST_SIZE, outlen);
154
+ EXPECT_EQ(std::string(expectedoutput, CBSASL_SHA512_DIGEST_SIZE),
155
+ std::string((const char *)outbuffer, CBSASL_SHA512_DIGEST_SIZE));
156
+ }
157
+
158
+ TEST_F(ScramTest, GenerateSaltedPasswordWithSHA256)
159
+ {
160
+ // here we check that the generate_salted_password function returns the expected output
161
+ // for a predefined password/salt/iteration count combination
162
+ union {
163
+ cbsasl_secret_t secret;
164
+ char buffer[30];
165
+ } u_auth;
166
+ unsigned char outbuffer[CBSASL_SHA256_DIGEST_SIZE];
167
+ unsigned int outlen;
168
+ const char *salt = "c2FsdA=="; // "salt" in base64
169
+ memcpy(u_auth.secret.data, "password", 8);
170
+ u_auth.secret.len = 8; // strlen("password")
171
+ // expected output was generated using the following Python algorithm:
172
+ // import hashlib, binascii
173
+ // dk = hashlib.pbkdf2_hmac('sha256', b'password', b'salt', 1000)
174
+ // print binascii.hexlify(dk)
175
+ const char *expectedoutput = "\x63\x2c\x28\x12\xe4\x6d\x46\x04\x10\x2b\xa7\x61\x8e\x9d\x6d"
176
+ "\x7d\x2f\x81\x28\xf6\x26\x6b\x4a\x03\x26\x4d\x2a\x04\x60\xb7"
177
+ "\xdc\xb3";
178
+
179
+ cbsasl_error_t ret = generate_salted_password(SASL_AUTH_MECH_SCRAM_SHA256, &u_auth.secret, salt, strlen(salt), 1000,
180
+ outbuffer, &outlen);
181
+ ASSERT_EQ(SASL_OK, ret);
182
+ EXPECT_EQ(CBSASL_SHA256_DIGEST_SIZE, outlen);
183
+ EXPECT_EQ(std::string(expectedoutput, CBSASL_SHA256_DIGEST_SIZE),
184
+ std::string((const char *)outbuffer, CBSASL_SHA256_DIGEST_SIZE));
185
+ }
186
+
187
+ TEST_F(ScramTest, GenerateSaltedPasswordWithSHA1)
188
+ {
189
+ // here we check that the generate_salted_password function returns the expected output
190
+ // for a predefined password/salt/iteration count combination
191
+ union {
192
+ cbsasl_secret_t secret;
193
+ char buffer[30];
194
+ } u_auth;
195
+ unsigned char outbuffer[CBSASL_SHA1_DIGEST_SIZE];
196
+ unsigned int outlen;
197
+ const char *salt = "c2FsdA=="; // "salt" in base64
198
+ memcpy(u_auth.secret.data, "password", 8);
199
+ u_auth.secret.len = 8; // strlen("password")
200
+ // expected output was generated using the following Python algorithm:
201
+ // import hashlib, binascii
202
+ // dk = hashlib.pbkdf2_hmac('sha1', b'password', b'salt', 1000)
203
+ // print binascii.hexlify(dk)
204
+ const char *expectedoutput = "\x6e\x88\xbe\x8b\xad\x7e\xae\x9d\x9e\x10\xaa\x06\x12\x24\x03"
205
+ "\x4f\xed\x48\xd0\x3f";
206
+
207
+ cbsasl_error_t ret = generate_salted_password(SASL_AUTH_MECH_SCRAM_SHA1, &u_auth.secret, salt, strlen(salt), 1000,
208
+ outbuffer, &outlen);
209
+ ASSERT_EQ(SASL_OK, ret);
210
+ EXPECT_EQ(CBSASL_SHA1_DIGEST_SIZE, outlen);
211
+ EXPECT_EQ(std::string(expectedoutput, CBSASL_SHA1_DIGEST_SIZE),
212
+ std::string((const char *)outbuffer, CBSASL_SHA1_DIGEST_SIZE));
213
+ }
214
+
215
+ TEST_F(ScramTest, ComputeClientProof_SHA512)
216
+ {
217
+ // we use the salted password computed in GenerateSaltedPasswordWithSHA512
218
+ const unsigned char *saltedpassword =
219
+ (const unsigned char *)"\xaf\xe6\xc5\x53\x07\x85\xb6\xcc\x6b\x1c\x64\x53\x38\x47\x31"
220
+ "\xbd\x5e\xe4\x32\xee\x54\x9f\xd4\x2f\xb6\x69\x57\x79\xad\x8a"
221
+ "\x1c\x5b\xf5\x9d\xe6\x9c\x48\xf7\x74\xef\xc4\x00\x7d\x52\x98"
222
+ "\xf9\x03\x3c\x02\x41\xd5\xab\x69\x30\x5e\x7b\x64\xec\xee\xb8"
223
+ "\xd8\x34\xcf\xec";
224
+ const char *clientfirstbare = "n=foo,r=001122334455667788";
225
+ const char *serverfirstmess = "r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000";
226
+ const char *clientfinalwithoutproof = "c=biws,r=00112233445566778899aabbccddeeff";
227
+ char *authmessage = NULL;
228
+ char outclientproof[(CBSASL_SHA512_DIGEST_SIZE / 3 + 1) * 4 + 1];
229
+
230
+ cbsasl_error_t ret =
231
+ compute_client_proof(SASL_AUTH_MECH_SCRAM_SHA512, saltedpassword, CBSASL_SHA512_DIGEST_SIZE, clientfirstbare,
232
+ strlen(clientfirstbare), serverfirstmess, strlen(serverfirstmess), clientfinalwithoutproof,
233
+ strlen(clientfinalwithoutproof), &authmessage, outclientproof, sizeof(outclientproof));
234
+
235
+ EXPECT_EQ(SASL_OK, ret);
236
+ // expected authentication message: concatenation of clientfirstbare, serverfirstmess and
237
+ // clientfinalwithoutproof (with commas)
238
+ const char *expectedauth = "n=foo,r=001122334455667788,"
239
+ "r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,"
240
+ "c=biws,r=00112233445566778899aabbccddeeff";
241
+
242
+ EXPECT_TRUE(authmessage != NULL);
243
+ EXPECT_STREQ(expectedauth, authmessage);
244
+
245
+ // expected client proof
246
+ // Here is how to generate the same value in Python 2.7:
247
+ // import hmac, hashlib, base64
248
+ // saltedpassword = '\xaf\xe6\xc5\x53\x07\x85\xb6\xcc\x6b\x1c\x64\x53\x38\x47\x31\xbd\x5e\xe4\x32\xee'\
249
+ // '\x54\x9f\xd4\x2f\xb6\x69\x57\x79\xad\x8a\x1c\x5b\xf5\x9d\xe6\x9c\x48\xf7\x74\xef'\
250
+ // '\xc4\x00\x7d\x52\x98\xf9\x03\x3c\x02\x41\xd5\xab\x69\x30\x5e\x7b\x64\xec\xee\xb8\xd8\x34\xcf\xec'
251
+ // clientkey = hmac.new(saltedpassword, 'Client Key', hashlib.sha512).digest()
252
+ // storedkey = hashlib.sha512(clientkey).digest()
253
+ // authmess='n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,c=biws,r=00112233445566778899aabbccddeeff'
254
+ // clientsign = hmac.new(storedkey, authmess, hashlib.sha512).digest()
255
+ // clientproof = ''.join(chr(ord(cs) ^ ord(ck)) for cs,ck in zip(clientsign, clientkey))
256
+ // print base64.b64encode(clientproof)
257
+ EXPECT_STREQ("dbXLc1MsNIdWj1AgSHRi/6E0OhWG2j6MwLKHR+UyVotT3G7VgYPlkQjwaewpH7v5BMXgkIqKRP/IUEbNA0M40w==",
258
+ outclientproof);
259
+
260
+ free(authmessage);
261
+ }
262
+
263
+ TEST_F(ScramTest, ComputeClientProof_SHA256)
264
+ {
265
+ // we use the salted password computed in GenerateSaltedPasswordWithSHA256
266
+ const unsigned char *saltedpassword =
267
+ (const unsigned char *)"\x63\x2c\x28\x12\xe4\x6d\x46\x04\x10\x2b\xa7\x61\x8e\x9d\x6d"
268
+ "\x7d\x2f\x81\x28\xf6\x26\x6b\x4a\x03\x26\x4d\x2a\x04\x60\xb7"
269
+ "\xdc\xb3";
270
+ const char *clientfirstbare = "n=foo,r=001122334455667788";
271
+ const char *serverfirstmess = "r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000";
272
+ const char *clientfinalwithoutproof = "c=biws,r=00112233445566778899aabbccddeeff";
273
+ char *authmessage = NULL;
274
+ char outclientproof[(CBSASL_SHA256_DIGEST_SIZE / 3 + 1) * 4 + 1];
275
+
276
+ cbsasl_error_t ret =
277
+ compute_client_proof(SASL_AUTH_MECH_SCRAM_SHA256, saltedpassword, CBSASL_SHA256_DIGEST_SIZE, clientfirstbare,
278
+ strlen(clientfirstbare), serverfirstmess, strlen(serverfirstmess), clientfinalwithoutproof,
279
+ strlen(clientfinalwithoutproof), &authmessage, outclientproof, sizeof(outclientproof));
280
+
281
+ EXPECT_EQ(SASL_OK, ret);
282
+ // expected authentication message: concatenation of clientfirstbare, serverfirstmess and
283
+ // clientfinalwithoutproof (with commas)
284
+ const char *expectedauth = "n=foo,r=001122334455667788,"
285
+ "r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,"
286
+ "c=biws,r=00112233445566778899aabbccddeeff";
287
+
288
+ EXPECT_TRUE(authmessage != NULL);
289
+ EXPECT_STREQ(expectedauth, authmessage);
290
+
291
+ // expected client proof
292
+ // Here is how to generate the same value in Python 2.7:
293
+ // import hmac, hashlib, base64
294
+ // saltedpassword = '\x63\x2c\x28\x12\xe4\x6d\x46\x04\x10\x2b\xa7\x61\x8e\x9d\x6d'\
295
+ // '\x7d\x2f\x81\x28\xf6\x26\x6b\x4a\x03\x26\x4d\x2a\x04\x60\xb7'\
296
+ // '\xdc\xb3'
297
+ // clientkey = hmac.new(saltedpassword, 'Client Key', hashlib.sha256).digest()
298
+ // storedkey = hashlib.sha256(clientkey).digest()
299
+ // authmess='n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,c=biws,r=00112233445566778899aabbccddeeff'
300
+ // clientsign = hmac.new(storedkey, authmess, hashlib.sha256).digest()
301
+ // clientproof = ''.join(chr(ord(cs) ^ ord(ck)) for cs,ck in zip(clientsign, clientkey))
302
+ // print base64.b64encode(clientproof)
303
+ EXPECT_STREQ("V2VMc1luh0OKg7VgRO2Wt7BoBUaW8ZxUhNav2RUbAHc=", outclientproof);
304
+
305
+ free(authmessage);
306
+ }
307
+
308
+ TEST_F(ScramTest, ComputeClientProof_SHA1)
309
+ {
310
+ // we use the salted password computed in GenerateSaltedPasswordWithSHA1
311
+ const unsigned char *saltedpassword =
312
+ (const unsigned char *)"\x6e\x88\xbe\x8b\xad\x7e\xae\x9d\x9e\x10\xaa\x06\x12\x24\x03"
313
+ "\x4f\xed\x48\xd0\x3f";
314
+ const char *clientfirstbare = "n=foo,r=001122334455667788";
315
+ const char *serverfirstmess = "r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000";
316
+ const char *clientfinalwithoutproof = "c=biws,r=00112233445566778899aabbccddeeff";
317
+ char *authmessage = NULL;
318
+ char outclientproof[(CBSASL_SHA1_DIGEST_SIZE / 3 + 1) * 4 + 1];
319
+
320
+ cbsasl_error_t ret =
321
+ compute_client_proof(SASL_AUTH_MECH_SCRAM_SHA1, saltedpassword, CBSASL_SHA1_DIGEST_SIZE, clientfirstbare,
322
+ strlen(clientfirstbare), serverfirstmess, strlen(serverfirstmess), clientfinalwithoutproof,
323
+ strlen(clientfinalwithoutproof), &authmessage, outclientproof, sizeof(outclientproof));
324
+
325
+ EXPECT_EQ(SASL_OK, ret);
326
+ // expected authentication message: concatenation of clientfirstbare, serverfirstmess and
327
+ // clientfinalwithoutproof (with commas)
328
+ const char *expectedauth = "n=foo,r=001122334455667788,"
329
+ "r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,"
330
+ "c=biws,r=00112233445566778899aabbccddeeff";
331
+
332
+ EXPECT_TRUE(authmessage != NULL);
333
+ EXPECT_STREQ(expectedauth, authmessage);
334
+
335
+ // expected client proof
336
+ // Here is how to generate the same value in Python 2.7:
337
+ // import hmac, hashlib, base64
338
+ // saltedpassword = '\x6e\x88\xbe\x8b\xad\x7e\xae\x9d\x9e\x10\xaa\x06\x12\x24\x03'\
339
+ // '\x4f\xed\x48\xd0\x3f'
340
+ // clientkey = hmac.new(saltedpassword, 'Client Key', hashlib.sha1).digest()
341
+ // storedkey = hashlib.sha1(clientkey).digest()
342
+ // authmess='n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,c=biws,r=00112233445566778899aabbccddeeff'
343
+ // clientsign = hmac.new(storedkey, authmess, hashlib.sha1).digest()
344
+ // clientproof = ''.join(chr(ord(cs) ^ ord(ck)) for cs,ck in zip(clientsign, clientkey))
345
+ // print base64.b64encode(clientproof)
346
+ EXPECT_STREQ("Iu9QH+CO2nAtVwmJaQe55UzlBEQ=", outclientproof);
347
+
348
+ free(authmessage);
349
+ }
350
+
351
+ TEST_F(ScramTest, ComputeServerSignature_SHA512)
352
+ {
353
+ // we use the salted password computed in GenerateSaltedPasswordWithSHA512
354
+ const unsigned char *saltedpassword =
355
+ (const unsigned char *)"\xaf\xe6\xc5\x53\x07\x85\xb6\xcc\x6b\x1c\x64\x53\x38\x47\x31"
356
+ "\xbd\x5e\xe4\x32\xee\x54\x9f\xd4\x2f\xb6\x69\x57\x79\xad\x8a"
357
+ "\x1c\x5b\xf5\x9d\xe6\x9c\x48\xf7\x74\xef\xc4\x00\x7d\x52\x98"
358
+ "\xf9\x03\x3c\x02\x41\xd5\xab\x69\x30\x5e\x7b\x64\xec\xee\xb8"
359
+ "\xd8\x34\xcf\xec";
360
+ const char *authmessage = "n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,"
361
+ "c=biws,r=00112233445566778899aabbccddeeff";
362
+ char outserversign[(CBSASL_SHA512_DIGEST_SIZE / 3 + 1) * 4 + 1];
363
+
364
+ cbsasl_error_t ret =
365
+ compute_server_signature(SASL_AUTH_MECH_SCRAM_SHA512, saltedpassword, CBSASL_SHA512_DIGEST_SIZE, authmessage,
366
+ outserversign, sizeof(outserversign));
367
+
368
+ EXPECT_EQ(SASL_OK, ret);
369
+
370
+ // expected client proof
371
+ // Here is how to generate the same value in Python 2.7:
372
+ // import hmac, hashlib, base64
373
+ // saltedpassword = '\xaf\xe6\xc5\x53\x07\x85\xb6\xcc\x6b\x1c\x64\x53\x38\x47\x31\xbd\x5e\xe4\x32\xee'\
374
+ // '\x54\x9f\xd4\x2f\xb6\x69\x57\x79\xad\x8a\x1c\x5b\xf5\x9d\xe6\x9c\x48\xf7\x74\xef'\
375
+ // '\xc4\x00\x7d\x52\x98\xf9\x03\x3c\x02\x41\xd5\xab\x69\x30\x5e\x7b\x64\xec\xee\xb8\xd8\x34\xcf\xec'
376
+ // serverkey = hmac.new(saltedpassword, 'Server Key', hashlib.sha512).digest()
377
+ // authmess='n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,c=biws,r=00112233445566778899aabbccddeeff'
378
+ // serversign = hmac.new(serverkey, authmess, hashlib.sha512).digest()
379
+ // print base64.b64encode(serversign)
380
+ EXPECT_STREQ("qonE7dZI6HvlX7nzSxbwmXBnr8xbw1pLhcwGFfnh+q1kqT+VoIood7EReeGXSog9Q9UNxqYKITudfYvSxJCQzg==",
381
+ outserversign);
382
+ }
383
+
384
+ TEST_F(ScramTest, ComputeServerSignature_SHA256)
385
+ {
386
+ // we use the salted password computed in GenerateSaltedPasswordWithSHA256
387
+ const unsigned char *saltedpassword =
388
+ (const unsigned char *)"\x63\x2c\x28\x12\xe4\x6d\x46\x04\x10\x2b\xa7\x61\x8e\x9d\x6d"
389
+ "\x7d\x2f\x81\x28\xf6\x26\x6b\x4a\x03\x26\x4d\x2a\x04\x60\xb7"
390
+ "\xdc\xb3";
391
+ const char *authmessage = "n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,"
392
+ "c=biws,r=00112233445566778899aabbccddeeff";
393
+ char outserversign[(CBSASL_SHA256_DIGEST_SIZE / 3 + 1) * 4 + 1];
394
+
395
+ cbsasl_error_t ret =
396
+ compute_server_signature(SASL_AUTH_MECH_SCRAM_SHA256, saltedpassword, CBSASL_SHA256_DIGEST_SIZE, authmessage,
397
+ outserversign, sizeof(outserversign));
398
+
399
+ EXPECT_EQ(SASL_OK, ret);
400
+
401
+ // expected client proof
402
+ // Here is how to generate the same value in Python 2.7:
403
+ // import hmac, hashlib, base64
404
+ // saltedpassword = '\x63\x2c\x28\x12\xe4\x6d\x46\x04\x10\x2b\xa7\x61\x8e\x9d\x6d'\
405
+ // '\x7d\x2f\x81\x28\xf6\x26\x6b\x4a\x03\x26\x4d\x2a\x04\x60\xb7'\
406
+ // '\xdc\xb3'
407
+ // serverkey = hmac.new(saltedpassword, 'Server Key', hashlib.sha256).digest()
408
+ // authmess='n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,c=biws,r=00112233445566778899aabbccddeeff'
409
+ // serversign = hmac.new(serverkey, authmess, hashlib.sha256).digest()
410
+ // print base64.b64encode(serversign)
411
+ EXPECT_STREQ("iPG9IiKPBI9165j9aGfbGM9FwHsANnspy5pMGJUbaS8=", outserversign);
412
+ }
413
+
414
+ TEST_F(ScramTest, ComputeServerSignature_SHA1)
415
+ {
416
+ // we use the salted password computed in GenerateSaltedPasswordWithSHA1
417
+ const unsigned char *saltedpassword =
418
+ (const unsigned char *)"\x6e\x88\xbe\x8b\xad\x7e\xae\x9d\x9e\x10\xaa\x06\x12\x24\x03"
419
+ "\x4f\xed\x48\xd0\x3f";
420
+ const char *authmessage = "n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,"
421
+ "c=biws,r=00112233445566778899aabbccddeeff";
422
+ char outserversign[(CBSASL_SHA1_DIGEST_SIZE / 3 + 1) * 4 + 1];
423
+
424
+ cbsasl_error_t ret = compute_server_signature(SASL_AUTH_MECH_SCRAM_SHA1, saltedpassword, CBSASL_SHA1_DIGEST_SIZE,
425
+ authmessage, outserversign, sizeof(outserversign));
426
+
427
+ EXPECT_EQ(SASL_OK, ret);
428
+
429
+ // expected client proof
430
+ // Here is how to generate the same value in Python 2.7:
431
+ // import hmac, hashlib, base64
432
+ // saltedpassword = '\x6e\x88\xbe\x8b\xad\x7e\xae\x9d\x9e\x10\xaa\x06\x12\x24\x03'\
433
+ // '\x4f\xed\x48\xd0\x3f'
434
+ // serverkey = hmac.new(saltedpassword, 'Server Key', hashlib.sha1).digest()
435
+ // authmess='n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,c=biws,r=00112233445566778899aabbccddeeff'
436
+ // serversign = hmac.new(serverkey, authmess, hashlib.sha1).digest()
437
+ // print base64.b64encode(serversign)
438
+ EXPECT_STREQ("WfiXP3zx55r8GXP1n2Bz/FVk/hk=", outserversign);
439
+ }
440
+
441
+ TEST_F(ScramTest, FinalServerCheck_SHA512)
442
+ {
443
+ // Testing cbsasl_client_check
444
+ cbsasl_conn_t ctx;
445
+ ctx.client = 1;
446
+ ctx.c.client.auth_mech = SASL_AUTH_MECH_SCRAM_SHA512;
447
+ // for computing the server signature, we only need the salted password and
448
+ // the authentication message
449
+ ctx.c.client.saltedpassword = (unsigned char *)"\xaf\xe6\xc5\x53\x07\x85\xb6\xcc\x6b\x1c\x64\x53\x38\x47\x31"
450
+ "\xbd\x5e\xe4\x32\xee\x54\x9f\xd4\x2f\xb6\x69\x57\x79\xad\x8a"
451
+ "\x1c\x5b\xf5\x9d\xe6\x9c\x48\xf7\x74\xef\xc4\x00\x7d\x52\x98"
452
+ "\xf9\x03\x3c\x02\x41\xd5\xab\x69\x30\x5e\x7b\x64\xec\xee\xb8"
453
+ "\xd8\x34\xcf\xec";
454
+ ctx.c.client.saltedpasslen = CBSASL_SHA512_DIGEST_SIZE;
455
+ ctx.c.client.auth_message =
456
+ (char *)"n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,"
457
+ "c=biws,r=00112233445566778899aabbccddeeff";
458
+ const char *invalid_sign =
459
+ "v=USEHlpFIwMJu0ytKPTmXPTXzZag82/F9qkAT2gB0gVaA00RTdQeSgCPhMVWcmvp7dhscVnkE/ZYLbDpMaeMp6g==";
460
+ EXPECT_EQ(SASL_FAIL, cbsasl_client_check(&ctx, invalid_sign, strlen(invalid_sign)));
461
+
462
+ const char *valid_sign =
463
+ "v=qonE7dZI6HvlX7nzSxbwmXBnr8xbw1pLhcwGFfnh+q1kqT+VoIood7EReeGXSog9Q9UNxqYKITudfYvSxJCQzg==";
464
+ EXPECT_EQ(SASL_OK, cbsasl_client_check(&ctx, valid_sign, strlen(valid_sign)));
465
+ }
466
+
467
+ TEST_F(ScramTest, FinalServerCheck_SHA256)
468
+ {
469
+ // Testing cbsasl_client_check
470
+ cbsasl_conn_t ctx;
471
+ ctx.client = 1;
472
+ ctx.c.client.auth_mech = SASL_AUTH_MECH_SCRAM_SHA256;
473
+ // for computing the server signature, we only need the salted password and
474
+ // the authentication message
475
+ ctx.c.client.saltedpassword = (unsigned char *)"\x63\x2c\x28\x12\xe4\x6d\x46\x04\x10\x2b\xa7\x61\x8e\x9d\x6d"
476
+ "\x7d\x2f\x81\x28\xf6\x26\x6b\x4a\x03\x26\x4d\x2a\x04\x60\xb7"
477
+ "\xdc\xb3";
478
+ ctx.c.client.saltedpasslen = CBSASL_SHA256_DIGEST_SIZE;
479
+ ctx.c.client.auth_message =
480
+ (char *)"n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,"
481
+ "c=biws,r=00112233445566778899aabbccddeeff";
482
+
483
+ const char *invalid_sign =
484
+ "v=USEHlpFIwMJu0ytKPTmXPTXzZag82/F9qkAT2gB0gVaA00RTdQeSgCPhMVWcmvp7dhscVnkE/ZYLbDpMaeMp6g==";
485
+ EXPECT_EQ(SASL_FAIL, cbsasl_client_check(&ctx, invalid_sign, strlen(invalid_sign)));
486
+
487
+ const char *valid_sign = "v=iPG9IiKPBI9165j9aGfbGM9FwHsANnspy5pMGJUbaS8=";
488
+ EXPECT_EQ(SASL_OK, cbsasl_client_check(&ctx, valid_sign, strlen(valid_sign)));
489
+ }
490
+
491
+ TEST_F(ScramTest, FinalServerCheck_SHA1)
492
+ {
493
+ // Testing cbsasl_client_check
494
+ cbsasl_conn_t ctx;
495
+ ctx.client = 1;
496
+ ctx.c.client.auth_mech = SASL_AUTH_MECH_SCRAM_SHA1;
497
+ // for computing the server signature, we only need the salted password and
498
+ // the authentication message
499
+ ctx.c.client.saltedpassword = (unsigned char *)"\x6e\x88\xbe\x8b\xad\x7e\xae\x9d\x9e\x10\xaa\x06\x12\x24\x03"
500
+ "\x4f\xed\x48\xd0\x3f";
501
+ ctx.c.client.saltedpasslen = CBSASL_SHA1_DIGEST_SIZE;
502
+ ctx.c.client.auth_message =
503
+ (char *)"n=foo,r=001122334455667788,r=00112233445566778899aabbccddeeff,s=c2FsdA==,i=1000,"
504
+ "c=biws,r=00112233445566778899aabbccddeeff";
505
+
506
+ const char *invalid_sign =
507
+ "v=USEHlpFIwMJu0ytKPTmXPTXzZag82/F9qkAT2gB0gVaA00RTdQeSgCPhMVWcmvp7dhscVnkE/ZYLbDpMaeMp6g==";
508
+ EXPECT_EQ(SASL_FAIL, cbsasl_client_check(&ctx, invalid_sign, strlen(invalid_sign)));
509
+
510
+ const char *valid_sign = "v=WfiXP3zx55r8GXP1n2Bz/FVk/hk=";
511
+ EXPECT_EQ(SASL_OK, cbsasl_client_check(&ctx, valid_sign, strlen(valid_sign)));
512
+ }
513
+
514
+ #endif // LCB_NO_SSL