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
@@ -24,6 +24,10 @@ void cbsasl_dispose(cbsasl_conn_t **conn)
24
24
  if (*conn != NULL) {
25
25
  if ((*conn)->client) {
26
26
  free((*conn)->c.client.userdata);
27
+ free((*conn)->c.client.nonce);
28
+ free((*conn)->c.client.client_first_message_bare);
29
+ free((*conn)->c.client.saltedpassword);
30
+ free((*conn)->c.client.auth_message);
27
31
  } else {
28
32
  free((*conn)->c.server.username);
29
33
  free((*conn)->c.server.config);
@@ -0,0 +1,500 @@
1
+ /*
2
+ * Copyright 2018 Couchbase, Inc.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include "scram_utils.h"
18
+ #include "config.h"
19
+ #include <time.h>
20
+ #include <ctype.h>
21
+
22
+ #include "strcodecs/strcodecs.h"
23
+
24
+ #ifndef LCB_NO_SSL
25
+ #include <openssl/rand.h>
26
+ #include <openssl/evp.h>
27
+ #include <openssl/hmac.h>
28
+ #include <openssl/sha.h>
29
+
30
+ #ifdef _WIN32
31
+ #include <process.h> // for _getpid
32
+ #else
33
+ #include <unistd.h> // for getpid
34
+ #endif
35
+
36
+ #endif
37
+
38
+ /**
39
+ * Ensures the seed for the random generator is correctly filled.
40
+ * Please note: as we use it only for the generation of the client nonce,
41
+ * we don't need a strong entropy.
42
+ */
43
+ void seed_rand(void)
44
+ {
45
+ // To keep the code as much platform-agnostic as possible, we use standard values
46
+ // like PID and current time for seeding the pseudo random generator.
47
+ // The entropy of these values is not good, but that's enough for generating nonces.
48
+
49
+ #ifdef LCB_NO_SSL
50
+ srand(time(NULL));
51
+ #else
52
+ time_t current_time = time(NULL);
53
+ clock_t clk;
54
+ #ifdef _WIN32
55
+ int pid;
56
+ #else
57
+ pid_t pid;
58
+ #endif
59
+ RAND_add(&current_time, sizeof(current_time), 0.0);
60
+ clk = clock();
61
+ RAND_add(&clk, sizeof(clk), 0.0);
62
+ #ifdef _WIN32
63
+ pid = _getpid();
64
+ #else
65
+ pid = getpid();
66
+ #endif // _WIN32
67
+ RAND_add(&pid, sizeof(pid), 0.0);
68
+ #endif // LCB_NO_SSL
69
+ }
70
+
71
+ /**
72
+ * Generates a binary nonce of 'buffer_length' bytes at the given buffer address.
73
+ * The buffer must be already allocated with enough space in it.
74
+ */
75
+ void generate_nonce(char *buffer, int buffer_length)
76
+ {
77
+ if ((NULL == buffer) || (0 == buffer_length)) {
78
+ // invalid input arguments
79
+ return;
80
+ }
81
+ seed_rand();
82
+
83
+ #ifndef LCB_NO_SSL
84
+ // we try first to use RAND_bytes from OpenSSL
85
+ if (!RAND_bytes((unsigned char *)buffer, buffer_length))
86
+ // RAND_bytes failed: we use the standard rand() function.
87
+ #endif
88
+ {
89
+ int aRandom = 0;
90
+ unsigned int aMaxRandBits = 0,
91
+ aMaxRand = RAND_MAX; // we have to compute how many bits the rand() function can return
92
+ unsigned int aRandRange = aMaxRandBits / 8; // number of bytes we can extract from a rand() value.
93
+ int i;
94
+ while (aMaxRand >>= 1) {
95
+ aMaxRandBits++;
96
+ }
97
+ // To avoid generating a new random number for each character, we call rand() only once every 5 characters.
98
+ // A 32-bits integer can give 5 values of 6 bits.
99
+ for (i = 0; i < buffer_length; ++i) {
100
+ if (i % aRandRange == 0) {
101
+ // we refill aRandom
102
+ aRandom = rand();
103
+ }
104
+ // we use only the last 8 bits of aRamdom
105
+ buffer[i] = (char)(aRandom & 0xFF);
106
+ aRandom >>= 8; // shift value by 8 bits
107
+ }
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Computes the number of comma (',') and equal ('=') characters in the input string
113
+ * for further substitution.
114
+ * Returns a negative value in case the buffer contains an invalid (control) character.
115
+ */
116
+ int compute_special_chars(const char *buffer, int buffer_length)
117
+ {
118
+ int result = 0;
119
+ int i;
120
+ for (i = 0; i < buffer_length; ++i) {
121
+ char c = buffer[i];
122
+ if (iscntrl(c)) {
123
+ return -1; // control characters are not allowed
124
+ }
125
+ switch (c) {
126
+ case '=':
127
+ case ',':
128
+ ++result;
129
+ break;
130
+ default:
131
+ break;
132
+ }
133
+ }
134
+ return result;
135
+ }
136
+
137
+ /**
138
+ * Copies 'n' bytes from 'src' to 'dest', replacing comma and equal characters by their
139
+ * substitution strings in the destination.
140
+ */
141
+ void usernmcpy(char *dest, const char *src, size_t n)
142
+ {
143
+ char *newdest = dest;
144
+ unsigned int i;
145
+
146
+ if (NULL == dest || NULL == src || 0 == n) {
147
+ return; // invalid arguments
148
+ }
149
+
150
+ for (i = 0; i < n; ++i) {
151
+ char c = src[i];
152
+ switch (c) {
153
+ case '=':
154
+ // '=' character is replaced by "=3D"
155
+ memcpy(newdest, "=3D", 3);
156
+ newdest += 3;
157
+ break;
158
+ case ',':
159
+ // '=' character is replaced by "=2C"
160
+ memcpy(newdest, "=2C", 3);
161
+ newdest += 3;
162
+ break;
163
+ default:
164
+ *newdest = c;
165
+ newdest++;
166
+ break;
167
+ }
168
+ }
169
+ }
170
+
171
+ /**
172
+ * Parses the server's first reply to extract the nonce, the salt and the iteration count.
173
+ */
174
+ cbsasl_error_t parse_server_challenge(const char *serverin, unsigned int serverinlen, const char **nonce,
175
+ unsigned int *noncelength, const char **salt, unsigned int *saltlength,
176
+ unsigned int *itcount)
177
+ {
178
+ const char *ptr = serverin;
179
+ const char *oldptr = serverin;
180
+ unsigned int remainlen = serverinlen;
181
+
182
+ if (NULL == serverin || 0 == serverinlen) {
183
+ return SASL_BADPARAM;
184
+ }
185
+
186
+ // the server challenge is normally composed of 3 attributes, separated by commas
187
+ do {
188
+ unsigned int attrlen; // attribute length
189
+ ptr = memchr(ptr, ',', remainlen);
190
+ if (ptr != NULL) {
191
+ // oldptr points to the beginning of the attribute
192
+ // Ex: "r=xxxxx,s=zzzzzz,i=10"
193
+ // ^ ^
194
+ // | |
195
+ // | +-- ptr
196
+ // +--------- oldptr
197
+ attrlen = ptr - oldptr;
198
+ ptr++; // to skip the comma
199
+ } else {
200
+ attrlen = remainlen;
201
+ }
202
+ if (attrlen <= 2) {
203
+ // invalid attribute
204
+ return SASL_BADPARAM;
205
+ }
206
+ // parse the attribute
207
+ if (oldptr[1] != '=') {
208
+ // invalid attribute: the second character must be an equal sign
209
+ return SASL_BADPARAM;
210
+ }
211
+ switch (oldptr[0]) {
212
+ case 'r': // nonce
213
+ if (*nonce != NULL) {
214
+ // it looks like we already stored a previous occurrence of the nonce attribute
215
+ return SASL_BADPARAM;
216
+ }
217
+ *nonce = oldptr + 2;
218
+ *noncelength = attrlen - 2;
219
+ break;
220
+ case 's': // salt
221
+ if (*salt != NULL) {
222
+ // it looks like we already stored a previous occurrence of the salt attribute
223
+ return SASL_BADPARAM;
224
+ }
225
+ *salt = oldptr + 2;
226
+ *saltlength = attrlen - 2;
227
+ break;
228
+ case 'i': // iteration count
229
+ {
230
+ // we have to use a temporary char array to parse the iteration count
231
+ char itcountstr[11]; // an integer has maximum ten digits
232
+ if (attrlen - 2 > 10) {
233
+ // value is larger than an integer
234
+ return SASL_BADPARAM;
235
+ }
236
+ memcpy(itcountstr, oldptr + 2, attrlen - 2);
237
+ itcountstr[attrlen - 2] = 0;
238
+ *itcount = atoi(itcountstr);
239
+ break;
240
+ }
241
+ default:
242
+ // invalid attribute type
243
+ return SASL_BADPARAM;
244
+ }
245
+
246
+ remainlen = remainlen - attrlen - 1;
247
+ oldptr = ptr;
248
+ } while (ptr != NULL);
249
+
250
+ return SASL_OK;
251
+ }
252
+
253
+ /**
254
+ * Generates the salted password.
255
+ * The 'outbuffer' buffer must be already allocated with enough space
256
+ * (CBSASL_SHA512_DIGEST_SIZE).
257
+ * As the salted password is binary and may contain the binary zero, we
258
+ * don't put a binary zero at the end of the buffer.
259
+ */
260
+ cbsasl_error_t generate_salted_password(cbsasl_auth_mechanism_t auth_mech, const cbsasl_secret_t *passwd,
261
+ const char *salt, unsigned int saltlen, unsigned int itcount,
262
+ unsigned char *outbuffer, unsigned int *outlength)
263
+ {
264
+ // decode the salt from Base64
265
+ char decodedsalt[256];
266
+ int decsaltlen = lcb_base64_decode(salt, saltlen, decodedsalt, sizeof(decodedsalt));
267
+ if (decsaltlen == -1) {
268
+ // could not decode the salt from base64
269
+ return SASL_BADPARAM;
270
+ }
271
+
272
+ #ifdef HAVE_PKCS5_PBKDF2_HMAC
273
+ switch (auth_mech) {
274
+ case SASL_AUTH_MECH_SCRAM_SHA1:
275
+ PKCS5_PBKDF2_HMAC((const char *)passwd->data, passwd->len, (const unsigned char *)decodedsalt,
276
+ (unsigned int)decsaltlen, itcount, EVP_sha1(), CBSASL_SHA1_DIGEST_SIZE, outbuffer);
277
+ *outlength = CBSASL_SHA1_DIGEST_SIZE;
278
+ break;
279
+ case SASL_AUTH_MECH_SCRAM_SHA256:
280
+ PKCS5_PBKDF2_HMAC((const char *)passwd->data, passwd->len, (const unsigned char *)decodedsalt,
281
+ (unsigned int)decsaltlen, itcount, EVP_sha256(), CBSASL_SHA256_DIGEST_SIZE, outbuffer);
282
+ *outlength = CBSASL_SHA256_DIGEST_SIZE;
283
+ break;
284
+ case SASL_AUTH_MECH_SCRAM_SHA512:
285
+ PKCS5_PBKDF2_HMAC((const char *)passwd->data, passwd->len, (const unsigned char *)decodedsalt,
286
+ (unsigned int)decsaltlen, itcount, EVP_sha512(), CBSASL_SHA512_DIGEST_SIZE, outbuffer);
287
+ *outlength = CBSASL_SHA512_DIGEST_SIZE;
288
+ break;
289
+ default:
290
+ return SASL_BADPARAM;
291
+ }
292
+ return SASL_OK;
293
+ #else
294
+ (void)auth_mech;
295
+ (void)passwd;
296
+ (void)salt;
297
+ (void)saltlen;
298
+ (void)itcount;
299
+ (void)outbuffer;
300
+ (void)outlength;
301
+
302
+ return SASL_BADPARAM;
303
+ #endif
304
+ }
305
+
306
+ #ifndef LCB_NO_SSL
307
+ /**
308
+ * Generates a HMAC digest of the key and data by using the given
309
+ * algorithm.
310
+ */
311
+ static cbsasl_error_t HMAC_digest(cbsasl_auth_mechanism_t auth_mech, const unsigned char *key, unsigned int keylen,
312
+ const unsigned char *data, unsigned int datalen, unsigned char *digest,
313
+ unsigned int *digestlen)
314
+ {
315
+ switch (auth_mech) {
316
+ case SASL_AUTH_MECH_SCRAM_SHA1:
317
+ if (HMAC(EVP_sha1(), key, keylen, data, datalen, digest, digestlen) == NULL) {
318
+ return SASL_FAIL;
319
+ }
320
+ break;
321
+ case SASL_AUTH_MECH_SCRAM_SHA256:
322
+ if (HMAC(EVP_sha256(), key, keylen, data, datalen, digest, digestlen) == NULL) {
323
+ return SASL_FAIL;
324
+ }
325
+ break;
326
+ case SASL_AUTH_MECH_SCRAM_SHA512:
327
+ if (HMAC(EVP_sha512(), key, keylen, data, datalen, digest, digestlen) == NULL) {
328
+ return SASL_FAIL;
329
+ }
330
+ break;
331
+ default:
332
+ return SASL_BADPARAM;
333
+ }
334
+ return SASL_OK;
335
+ }
336
+ #endif
337
+
338
+ /**
339
+ * Computes the client proof. It is computed as:
340
+ *
341
+ * ClientKey := HMAC(SaltedPassword, "Client Key")
342
+ * StoredKey := H(ClientKey)
343
+ * AuthMessage := client-first-message-bare + "," +
344
+ * server-first-message + "," +
345
+ * client-final-message-without-proof
346
+ * ClientSignature := HMAC(StoredKey, AuthMessage)
347
+ * ClientProof := ClientKey XOR ClientSignature
348
+ */
349
+ cbsasl_error_t compute_client_proof(cbsasl_auth_mechanism_t auth_mech, const unsigned char *saltedpassword,
350
+ unsigned int saltedpasslen, const char *clientfirstbare, unsigned int cfblen,
351
+ const char *serverfirstmess, unsigned int sfmlen,
352
+ const char *clientfinalwithoutproof, unsigned int cfwplen, char **authmessage,
353
+ char *outclientproof, unsigned int outprooflen)
354
+ {
355
+ #ifndef LCB_NO_SSL
356
+ const char *clientkeystr = "Client Key";
357
+ unsigned char clientkeyhmac[EVP_MAX_MD_SIZE];
358
+ unsigned int hmaclen = 0;
359
+ // we first compute the client key
360
+ // ClientKey := HMAC(SaltedPassword, "Client Key")
361
+ cbsasl_error_t ret = HMAC_digest(auth_mech, saltedpassword, saltedpasslen, (const unsigned char *)clientkeystr,
362
+ strlen(clientkeystr), clientkeyhmac, &hmaclen);
363
+ if (ret != SASL_OK) {
364
+ return ret;
365
+ }
366
+
367
+ // then we hashes the client key to compute the storey key
368
+ // StoredKey := H(ClientKey)
369
+ unsigned char storedkey[EVP_MAX_MD_SIZE];
370
+ unsigned int storedkeylen = 0;
371
+ switch (auth_mech) {
372
+ case SASL_AUTH_MECH_SCRAM_SHA1:
373
+ if (SHA1(clientkeyhmac, hmaclen, storedkey) == NULL) {
374
+ return SASL_FAIL;
375
+ }
376
+ storedkeylen = SHA_DIGEST_LENGTH;
377
+ break;
378
+ case SASL_AUTH_MECH_SCRAM_SHA256:
379
+ if (SHA256(clientkeyhmac, hmaclen, storedkey) == NULL) {
380
+ return SASL_FAIL;
381
+ }
382
+ storedkeylen = SHA256_DIGEST_LENGTH;
383
+ break;
384
+ case SASL_AUTH_MECH_SCRAM_SHA512:
385
+ if (SHA512(clientkeyhmac, hmaclen, storedkey) == NULL) {
386
+ return SASL_FAIL;
387
+ }
388
+ storedkeylen = SHA512_DIGEST_LENGTH;
389
+ break;
390
+ default:
391
+ return SASL_BADPARAM;
392
+ }
393
+
394
+ // now we can compute the AuthMessage
395
+ // AuthMessage := client-first-message-bare + "," +
396
+ // server-first-message + "," +
397
+ // client-final-message-without-proof
398
+ unsigned int authmesslen = cfblen + 1 + sfmlen + 1 + cfwplen;
399
+ char *authmess = calloc(authmesslen + 1, 1); // +1 for the binary zero
400
+ if (NULL == authmess) {
401
+ return SASL_NOMEM;
402
+ }
403
+ memcpy(authmess, clientfirstbare, cfblen);
404
+ authmess[cfblen] = ',';
405
+ memcpy(authmess + cfblen + 1, serverfirstmess, sfmlen);
406
+ authmess[cfblen + 1 + sfmlen] = ',';
407
+ memcpy(authmess + cfblen + 1 + sfmlen + 1, clientfinalwithoutproof, cfwplen);
408
+ *authmessage = authmess; // save the buffer into the context area for later use
409
+
410
+ // let's compute the client signature
411
+ // ClientSignature := HMAC(StoredKey, AuthMessage)
412
+ unsigned char clientsign[EVP_MAX_MD_SIZE];
413
+ unsigned int clientsignlen = 0;
414
+ ret = HMAC_digest(auth_mech, storedkey, storedkeylen, (const unsigned char *)authmess, authmesslen, clientsign,
415
+ &clientsignlen);
416
+ if (ret != SASL_OK) {
417
+ return ret;
418
+ }
419
+
420
+ // final step:
421
+ // ClientProof := ClientKey XOR ClientSignature
422
+ char clientproof[EVP_MAX_MD_SIZE]; // binary client proof
423
+ for (unsigned int i = 0; i < clientsignlen; ++i) {
424
+ clientproof[i] = clientkeyhmac[i] ^ clientsign[i];
425
+ }
426
+
427
+ // the final client proof must be encoded in base64
428
+ if (lcb_base64_encode(clientproof, clientsignlen, outclientproof, outprooflen)) {
429
+ return SASL_FAIL;
430
+ }
431
+ // and we are done
432
+
433
+ #else
434
+ // nothing to do if OpenSSL is not present
435
+ (void)auth_mech;
436
+ (void)saltedpassword;
437
+ (void)saltedpasslen;
438
+ (void)clientfirstbare;
439
+ (void)cfblen;
440
+ (void)serverfirstmess;
441
+ (void)sfmlen;
442
+ (void)clientfinalwithoutproof;
443
+ (void)cfwplen;
444
+ (void)authmessage;
445
+ (void)outclientproof;
446
+ (void)outprooflen;
447
+ #endif
448
+ return SASL_OK;
449
+ }
450
+
451
+ /**
452
+ * Computes the Server Signature. It is computed as:
453
+ *
454
+ * SaltedPassword := Hi(Normalize(password), salt, i)
455
+ * ServerKey := HMAC(SaltedPassword, "Server Key")
456
+ * ServerSignature := HMAC(ServerKey, AuthMessage)
457
+ */
458
+ cbsasl_error_t compute_server_signature(cbsasl_auth_mechanism_t auth_mech, const unsigned char *saltedpassword,
459
+ unsigned int saltedpasslen, const char *authmessage, char *outserversign,
460
+ unsigned int outsignlen)
461
+ {
462
+ #ifndef LCB_NO_SSL
463
+ const char *serverkeystr = "Server Key";
464
+ unsigned char serverkeyhmac[EVP_MAX_MD_SIZE];
465
+ unsigned int hmaclen = 0;
466
+ // we first compute the server key
467
+ // ServerKey := HMAC(SaltedPassword, "Server Key")
468
+ cbsasl_error_t ret = HMAC_digest(auth_mech, saltedpassword, saltedpasslen, (unsigned char *)serverkeystr,
469
+ strlen(serverkeystr), serverkeyhmac, &hmaclen);
470
+ if (ret != SASL_OK) {
471
+ return ret;
472
+ }
473
+
474
+ // let's compute the server signature
475
+ // ServerSignature := HMAC(ServerKey, AuthMessage)
476
+ unsigned char serversign[EVP_MAX_MD_SIZE];
477
+ unsigned int serversignlen = 0;
478
+ ret = HMAC_digest(auth_mech, serverkeyhmac, hmaclen, (unsigned char *)authmessage, strlen(authmessage), serversign,
479
+ &serversignlen);
480
+ if (ret != SASL_OK) {
481
+ return ret;
482
+ }
483
+
484
+ // the final client signature must be encoded in base64
485
+ if (lcb_base64_encode((const char *)serversign, serversignlen, outserversign, outsignlen)) {
486
+ return SASL_FAIL;
487
+ }
488
+ // and we are done
489
+
490
+ #else
491
+ // nothing to do if OpenSSL is not present
492
+ (void)auth_mech;
493
+ (void)saltedpassword;
494
+ (void)saltedpasslen;
495
+ (void)authmessage;
496
+ (void)outserversign;
497
+ (void)outsignlen;
498
+ #endif
499
+ return SASL_OK;
500
+ }