libcouchbase 1.2.8 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
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