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
@@ -21,6 +21,7 @@ FILE(GLOB LCB_OP_SRC src/operations/*.c)
21
21
 
22
22
  # memcached packets
23
23
  FILE(GLOB LCB_MC_SRC src/mc/*.c)
24
+ FILE(GLOB LCB_MC_CXXSRC src/mc/*.cc)
24
25
 
25
26
  # read buffer management
26
27
  FILE(GLOB LCB_RDB_SRC src/rdb/*.c)
@@ -40,11 +41,14 @@ SET(LCB_CORE_SRC
40
41
  ${LCB_N1QL_SRC}
41
42
  src/callbacks.c
42
43
  src/legacy.c
43
- # src/mcserver/negotiate.c
44
44
  src/iofactory.c
45
45
  src/settings.c
46
46
  src/utilities.c)
47
47
 
48
+ IF (LCB_TRACING)
49
+ FILE(GLOB LCB_TRACING_SRC src/tracing/*.cc)
50
+ ENDIF()
51
+
48
52
  SET(LCB_CORE_CXXSRC
49
53
  src/instance.cc
50
54
  src/auth.cc
@@ -55,6 +59,7 @@ SET(LCB_CORE_CXXSRC
55
59
  src/bucketconfig/bc_static.cc
56
60
  src/bucketconfig/confmon.cc
57
61
  src/connspec.cc
62
+ src/crypto.cc
58
63
  src/dns-srv.cc
59
64
  src/dump.cc
60
65
  src/errmap.cc
@@ -87,9 +92,13 @@ SET(LCB_CORE_CXXSRC
87
92
  src/operations/ping.cc
88
93
  src/mcserver/mcserver.cc
89
94
  src/mcserver/negotiate.cc
95
+ src/metrics.cc
90
96
  src/retrychk.cc
91
97
  src/retryq.cc
98
+ src/rnd.cc
92
99
  src/views/docreq.cc
93
100
  src/views/viewreq.cc
94
101
  src/cntl.cc
95
- src/wait.cc)
102
+ src/wait.cc
103
+ ${LCB_TRACING_SRC}
104
+ )
@@ -1,9 +1,25 @@
1
+ INCLUDE (CheckCSourceCompiles)
1
2
  INCLUDE_DIRECTORIES(src)
2
3
  FILE(GLOB CBSASL_SRC src/*.c)
3
4
  FILE(GLOB CRAM_SRC src/cram-md5/*.c)
5
+ FILE(GLOB SCRAM_SRC src/scram-sha/*.c)
4
6
 
5
- ADD_LIBRARY(cbsasl OBJECT ${CBSASL_SRC} ${CRAM_SRC})
6
- SET_TARGET_PROPERTIES(cbsasl
7
+ ADD_LIBRARY(cbsasl-lcb OBJECT ${CBSASL_SRC} ${CRAM_SRC} ${SCRAM_SRC})
8
+ SET_TARGET_PROPERTIES(cbsasl-lcb
7
9
  PROPERTIES
8
10
  POSITION_INDEPENDENT_CODE TRUE
9
11
  COMPILE_FLAGS "${LCB_CORE_CFLAGS}")
12
+
13
+ IF(OPENSSL_FOUND AND (NOT LCB_NO_SSL))
14
+ INCLUDE_DIRECTORIES(${OPENSSL_INCLUDE_DIR})
15
+ ADD_DEFINITIONS(${OPENSSL_DEFINITIONS})
16
+ # Check if the system have a usable version of PKCS5_PBKDF2_HMAC
17
+ CMAKE_PUSH_CHECK_STATE(RESET)
18
+ SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${OPENSSL_LIBRARIES})
19
+ SET(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${OPENSSL_INCLUDE_DIR})
20
+ CHECK_C_SOURCE_COMPILES("
21
+ #include <openssl/evp.h>
22
+ int main() {
23
+ PKCS5_PBKDF2_HMAC(NULL, 0, NULL, 0, 0, NULL, 0, NULL);
24
+ }" HAVE_PKCS5_PBKDF2_HMAC)
25
+ ENDIF()
@@ -22,6 +22,19 @@
22
22
  extern "C" {
23
23
  #endif
24
24
 
25
+ #define MECH_PLAIN "PLAIN"
26
+ #define MECH_CRAM_MD5 "CRAM-MD5"
27
+ #define MECH_SCRAM_SHA1 "SCRAM-SHA1"
28
+ #define MECH_SCRAM_SHA256 "SCRAM-SHA256"
29
+ #define MECH_SCRAM_SHA512 "SCRAM-SHA512"
30
+
31
+ // size in bytes - to double if the nonce is displayed in hexadecimal
32
+ #define SCRAM_NONCE_SIZE 8
33
+
34
+ #define CBSASL_SHA1_DIGEST_SIZE 20
35
+ #define CBSASL_SHA256_DIGEST_SIZE 32
36
+ #define CBSASL_SHA512_DIGEST_SIZE 64
37
+
25
38
  typedef enum cbsasl_error {
26
39
  SASL_OK,
27
40
  SASL_CONTINUE,
@@ -33,6 +46,15 @@ extern "C" {
33
46
  }
34
47
  cbsasl_error_t;
35
48
 
49
+ typedef enum cbsasl_auth_mechanism {
50
+ SASL_AUTH_MECH_PLAIN,
51
+ SASL_AUTH_MECH_CRAM_MD5, // deprecated
52
+ SASL_AUTH_MECH_SCRAM_SHA1,
53
+ SASL_AUTH_MECH_SCRAM_SHA256,
54
+ SASL_AUTH_MECH_SCRAM_SHA512
55
+ }
56
+ cbsasl_auth_mechanism_t;
57
+
36
58
  typedef struct {
37
59
  unsigned long len;
38
60
  unsigned char data[1];
@@ -60,13 +82,18 @@ extern "C" {
60
82
 
61
83
  struct cbsasl_client_conn_t {
62
84
  char *userdata;
63
- int plain;
85
+ cbsasl_auth_mechanism_t auth_mech; // authentication mechanism
64
86
  int (*get_username)(void *context, int id, const char **result,
65
87
  unsigned int *len);
66
88
  void *get_username_ctx;
67
89
  int (*get_password)(cbsasl_conn_t *conn, void *context, int id,
68
90
  cbsasl_secret_t **psecret);
69
91
  void *get_password_ctx;
92
+ char *nonce; // client nonce for SCRAM-SHA authentication
93
+ char *client_first_message_bare; // for SCRAM-SHA authentication
94
+ unsigned char *saltedpassword; // for SCRAM-SHA authentication
95
+ unsigned int saltedpasslen; // length of the salted password field
96
+ char *auth_message; // for SCRAM-SHA authentication
70
97
  };
71
98
 
72
99
  struct cbsasl_server_conn_t {
@@ -143,6 +170,20 @@ extern "C" {
143
170
  const char **output,
144
171
  unsigned *outputlen);
145
172
 
173
+ /**
174
+ * Final authentication step, if need to be (depending on the mechanism).
175
+ *
176
+ * This is mainly use for SCRAM-SHA authentication family, to verify the
177
+ * server signature. Even if the server accepted the authentication, if
178
+ * we can't verify its signature, we must reject the connection.
179
+ *
180
+ * @return Whether or not the sasl check was successful
181
+ */
182
+ CBSASL_PUBLIC_API
183
+ cbsasl_error_t cbsasl_client_check(cbsasl_conn_t *conn,
184
+ const char *input,
185
+ unsigned int inputlen);
186
+
146
187
  /**
147
188
  * Frees up funushed sasl connections
148
189
  *
@@ -199,7 +240,8 @@ extern "C" {
199
240
  void **prompt_need,
200
241
  const char **clientout,
201
242
  unsigned int *clientoutlen,
202
- const char **mech);
243
+ const char **mech,
244
+ int allow_scram_sha);
203
245
 
204
246
  CBSASL_PUBLIC_API
205
247
  cbsasl_error_t cbsasl_client_step(cbsasl_conn_t *conn,
@@ -14,24 +14,23 @@
14
14
  * limitations under the License.
15
15
  */
16
16
 
17
+ #include "config.h"
17
18
  #include "cbsasl/cbsasl.h"
18
19
  #include "cram-md5/hmac.h"
20
+ #include "scram-sha/scram_utils.h"
19
21
  #include "util.h"
20
22
  #include <time.h>
21
23
  #include <stdlib.h>
22
24
  #include <string.h>
25
+ #include <stdio.h>
23
26
 
24
27
  CBSASL_PUBLIC_API
25
- cbsasl_error_t cbsasl_client_new(const char *service,
26
- const char *serverFQDN,
27
- const char *iplocalport,
28
- const char *ipremoteport,
29
- const cbsasl_callback_t *prompt_supp,
30
- unsigned flags,
28
+ cbsasl_error_t cbsasl_client_new(const char *service, const char *serverFQDN, const char *iplocalport,
29
+ const char *ipremoteport, const cbsasl_callback_t *prompt_supp, unsigned flags,
31
30
  cbsasl_conn_t **pconn)
32
31
  {
33
32
  cbsasl_conn_t *conn;
34
- cbsasl_callback_t *callbacks = (cbsasl_callback_t*)prompt_supp;
33
+ cbsasl_callback_t *callbacks = (cbsasl_callback_t *)prompt_supp;
35
34
  int ii;
36
35
 
37
36
  if (prompt_supp == NULL) {
@@ -85,63 +84,138 @@ cbsasl_error_t cbsasl_client_new(const char *service,
85
84
  }
86
85
 
87
86
  CBSASL_PUBLIC_API
88
- cbsasl_error_t cbsasl_client_start(cbsasl_conn_t *conn,
89
- const char *mechlist,
90
- void **prompt_need,
91
- const char **clientout,
92
- unsigned int *clientoutlen,
93
- const char **mech)
87
+ cbsasl_error_t cbsasl_client_start(cbsasl_conn_t *conn, const char *mechlist, void **prompt_need,
88
+ const char **clientout, unsigned int *clientoutlen, const char **mech,
89
+ int allow_scram_sha)
94
90
  {
95
91
  if (conn->client == 0) {
96
92
  return SASL_BADPARAM;
97
93
  }
98
94
 
99
- if (strstr(mechlist, "CRAM-MD5") == NULL) {
100
- if (strstr(mechlist, "PLAIN") == NULL) {
95
+ *mech = NULL;
96
+ if (allow_scram_sha) {
97
+ #if !defined(LCB_NO_SSL) && defined(HAVE_PKCS5_PBKDF2_HMAC)
98
+ // we use SCRAM-SHA only if OpenSSL is linked and has support for PBKDF2_HMAC functions
99
+ if (strstr(mechlist, MECH_SCRAM_SHA512) != NULL) {
100
+ *mech = MECH_SCRAM_SHA512;
101
+ conn->c.client.auth_mech = SASL_AUTH_MECH_SCRAM_SHA512;
102
+ } else if (strstr(mechlist, MECH_SCRAM_SHA256) != NULL) {
103
+ *mech = MECH_SCRAM_SHA256;
104
+ conn->c.client.auth_mech = SASL_AUTH_MECH_SCRAM_SHA256;
105
+ } else if (strstr(mechlist, MECH_SCRAM_SHA1) != NULL) {
106
+ *mech = MECH_SCRAM_SHA1;
107
+ conn->c.client.auth_mech = SASL_AUTH_MECH_SCRAM_SHA1;
108
+ }
109
+ #endif
110
+ }
111
+ if (*mech == NULL) {
112
+ if (strstr(mechlist, MECH_CRAM_MD5) != NULL) {
113
+ *mech = MECH_CRAM_MD5;
114
+ conn->c.client.auth_mech = SASL_AUTH_MECH_CRAM_MD5;
115
+ } else if (strstr(mechlist, MECH_PLAIN) != NULL) {
116
+ *mech = MECH_PLAIN;
117
+ conn->c.client.auth_mech = SASL_AUTH_MECH_PLAIN;
118
+ } else {
101
119
  return SASL_NOMECH;
102
120
  }
103
-
104
- *mech = "PLAIN";
105
- conn->c.client.plain = 1;
106
- } else {
107
- *mech = "CRAM-MD5";
108
- conn->c.client.plain = 0;
109
121
  }
110
122
 
123
+ switch (conn->c.client.auth_mech) {
124
+ case SASL_AUTH_MECH_PLAIN: {
125
+ const char *usernm = NULL;
126
+ unsigned int usernmlen;
127
+ cbsasl_secret_t *pass;
128
+ cbsasl_error_t ret;
111
129
 
112
- if (conn->c.client.plain) {
113
- const char *usernm = NULL;
114
- unsigned int usernmlen;
115
- cbsasl_secret_t *pass;
130
+ ret = conn->c.client.get_username(conn->c.client.get_username_ctx, CBSASL_CB_USER, &usernm, &usernmlen);
131
+ if (ret != SASL_OK) {
132
+ return ret;
133
+ }
116
134
 
117
- cbsasl_error_t ret;
118
- ret = conn->c.client.get_username(conn->c.client.get_username_ctx,
119
- CBSASL_CB_USER,
120
- &usernm, &usernmlen);
121
- if (ret != SASL_OK) {
122
- return ret;
123
- }
135
+ ret = conn->c.client.get_password(conn, conn->c.client.get_password_ctx, CBSASL_CB_PASS, &pass);
136
+ if (ret != SASL_OK) {
137
+ return ret;
138
+ }
124
139
 
125
- ret = conn->c.client.get_password(conn, conn->c.client.get_password_ctx,
126
- CBSASL_CB_PASS,
127
- &pass);
128
- if (ret != SASL_OK) {
129
- return ret;
130
- }
140
+ conn->c.client.userdata = calloc(usernmlen + 1 + pass->len + 1, 1);
141
+ if (conn->c.client.userdata == NULL) {
142
+ return SASL_NOMEM;
143
+ }
131
144
 
132
- conn->c.client.userdata = calloc(usernmlen + 1 + pass->len + 1, 1);
133
- if (conn->c.client.userdata == NULL) {
134
- return SASL_NOMEM;
145
+ memcpy(conn->c.client.userdata + 1, usernm, usernmlen);
146
+ memcpy(conn->c.client.userdata + usernmlen + 2, pass->data, pass->len);
147
+ *clientout = conn->c.client.userdata;
148
+ *clientoutlen = (unsigned int)(usernmlen + 2 + pass->len);
149
+ break;
135
150
  }
151
+ case SASL_AUTH_MECH_SCRAM_SHA1:
152
+ case SASL_AUTH_MECH_SCRAM_SHA256:
153
+ case SASL_AUTH_MECH_SCRAM_SHA512: {
154
+ const char *usernm = NULL;
155
+ unsigned int usernmlen;
156
+ int usernmspeccharsnb;
157
+ char binnonce[SCRAM_NONCE_SIZE]; // binary nonce
158
+ cbsasl_error_t ret;
159
+
160
+ ret = conn->c.client.get_username(conn->c.client.get_username_ctx, CBSASL_CB_USER, &usernm, &usernmlen);
161
+ if (ret != SASL_OK) {
162
+ return ret;
163
+ }
164
+ usernmspeccharsnb = compute_special_chars(usernm, usernmlen);
165
+ if (usernmspeccharsnb < 0) {
166
+ // invalid characters in the username
167
+ return SASL_BADPARAM;
168
+ }
169
+
170
+ generate_nonce(binnonce, SCRAM_NONCE_SIZE);
171
+ conn->c.client.nonce = calloc(SCRAM_NONCE_SIZE * 2 + 1, 1);
172
+ if (conn->c.client.nonce == NULL) {
173
+ return SASL_NOMEM;
174
+ }
175
+ // stores binary nonce in hexadecimal format into conn->c.client.nonce array
176
+ cbsasl_hex_encode(conn->c.client.nonce, binnonce, SCRAM_NONCE_SIZE);
177
+ conn->c.client.nonce[SCRAM_NONCE_SIZE * 2] = '\0';
136
178
 
137
- memcpy(conn->c.client.userdata + 1, usernm, usernmlen);
138
- memcpy(conn->c.client.userdata + usernmlen + 2, pass->data, pass->len);
139
- *clientout = conn->c.client.userdata;
140
- *clientoutlen = (unsigned int)(usernmlen + 2 + pass->len);
141
- } else {
142
- /* CRAM-MD5 */
143
- *clientout = NULL;
144
- *clientoutlen = 0;
179
+ #define GS2_HEADER "n,,n=" // "no binding" + start of name attribute
180
+ #define NONCE_ATTR ",r=" // start of nonce attribute
181
+ conn->c.client.userdata = calloc(
182
+ strlen(GS2_HEADER) + usernmlen + usernmspeccharsnb * 2 + strlen(NONCE_ATTR) + SCRAM_NONCE_SIZE * 2, 1);
183
+ if (conn->c.client.userdata == NULL) {
184
+ return SASL_NOMEM;
185
+ }
186
+
187
+ memcpy(conn->c.client.userdata, GS2_HEADER, strlen(GS2_HEADER));
188
+ if (!usernmspeccharsnb) {
189
+ // no special char, we can do a direct copy
190
+ memcpy(conn->c.client.userdata + strlen(GS2_HEADER), usernm, usernmlen);
191
+ } else {
192
+ // copy with substitution of special characters
193
+ usernmcpy(conn->c.client.userdata + strlen(GS2_HEADER), usernm, usernmlen);
194
+ }
195
+ memcpy(conn->c.client.userdata + strlen(GS2_HEADER) + usernmlen + usernmspeccharsnb * 2, NONCE_ATTR,
196
+ strlen(NONCE_ATTR));
197
+ memcpy(conn->c.client.userdata + strlen(GS2_HEADER) + usernmlen + usernmspeccharsnb * 2 +
198
+ strlen(NONCE_ATTR),
199
+ conn->c.client.nonce, SCRAM_NONCE_SIZE * 2);
200
+
201
+ *clientout = conn->c.client.userdata;
202
+ *clientoutlen = (unsigned int)(strlen(GS2_HEADER) + usernmlen + usernmspeccharsnb * 2 + strlen(NONCE_ATTR) +
203
+ SCRAM_NONCE_SIZE * 2);
204
+
205
+ // save the client first message for later step (without the first three characters)
206
+ conn->c.client.client_first_message_bare = calloc(*clientoutlen - 3 + 1, 1); // +1 for the binary zero
207
+ if (conn->c.client.client_first_message_bare == NULL) {
208
+ return SASL_NOMEM;
209
+ }
210
+ memcpy(conn->c.client.client_first_message_bare, *clientout + 3, *clientoutlen - 3);
211
+ // no need to add a final binary zero, as calloc already sets the memory to zero
212
+ break;
213
+ }
214
+ case SASL_AUTH_MECH_CRAM_MD5:
215
+ // no data in the first CRAM-MD5 message
216
+ *clientout = NULL;
217
+ *clientoutlen = 0;
218
+ break;
145
219
  }
146
220
 
147
221
  (void)prompt_need;
@@ -149,15 +223,9 @@ cbsasl_error_t cbsasl_client_start(cbsasl_conn_t *conn,
149
223
  }
150
224
 
151
225
  CBSASL_PUBLIC_API
152
- cbsasl_error_t cbsasl_client_step(cbsasl_conn_t *conn,
153
- const char *serverin,
154
- unsigned int serverinlen,
155
- void **not_used,
156
- const char **clientout,
157
- unsigned int *clientoutlen)
226
+ cbsasl_error_t cbsasl_client_step(cbsasl_conn_t *conn, const char *serverin, unsigned int serverinlen, void **not_used,
227
+ const char **clientout, unsigned int *clientoutlen)
158
228
  {
159
- unsigned char digest[DIGEST_LENGTH];
160
- char md5string[DIGEST_LENGTH * 2];
161
229
  const char *usernm = NULL;
162
230
  unsigned int usernmlen;
163
231
  cbsasl_secret_t *pass;
@@ -169,39 +237,183 @@ cbsasl_error_t cbsasl_client_step(cbsasl_conn_t *conn,
169
237
  return SASL_BADPARAM;
170
238
  }
171
239
 
172
- if (conn->c.client.plain) {
240
+ if (conn->c.client.auth_mech == SASL_AUTH_MECH_PLAIN) {
173
241
  /* Shouldn't be called during plain auth */
174
242
  return SASL_BADPARAM;
175
243
  }
176
244
 
177
- ret = conn->c.client.get_username(conn->c.client.get_username_ctx,
178
- CBSASL_CB_USER, &usernm, &usernmlen);
245
+ ret = conn->c.client.get_username(conn->c.client.get_username_ctx, CBSASL_CB_USER, &usernm, &usernmlen);
179
246
  if (ret != SASL_OK) {
180
247
  return ret;
181
248
  }
182
249
 
183
- ret = conn->c.client.get_password(conn, conn->c.client.get_password_ctx,
184
- CBSASL_CB_PASS, &pass);
250
+ ret = conn->c.client.get_password(conn, conn->c.client.get_password_ctx, CBSASL_CB_PASS, &pass);
185
251
  if (ret != SASL_OK) {
186
252
  return ret;
187
253
  }
188
254
 
189
255
  free(conn->c.client.userdata);
190
- conn->c.client.userdata = calloc(usernmlen + 1 + sizeof(md5string) + 1, 1);
191
- if (conn->c.client.userdata == NULL) {
192
- return SASL_NOMEM;
193
- }
256
+ conn->c.client.userdata = NULL;
257
+ switch (conn->c.client.auth_mech) {
258
+ case SASL_AUTH_MECH_CRAM_MD5: {
259
+ unsigned char digest[DIGEST_LENGTH];
260
+ char md5string[DIGEST_LENGTH * 2];
261
+ conn->c.client.userdata = calloc(usernmlen + 1 + sizeof(md5string) + 1, 1);
262
+ if (conn->c.client.userdata == NULL) {
263
+ return SASL_NOMEM;
264
+ }
194
265
 
195
- cbsasl_hmac_md5((unsigned char*)serverin, serverinlen, pass->data,
196
- pass->len, digest);
197
- cbsasl_hex_encode(md5string, (char *) digest, DIGEST_LENGTH);
198
- memcpy(conn->c.client.userdata, usernm, usernmlen);
199
- conn->c.client.userdata[usernmlen] = ' ';
200
- memcpy(conn->c.client.userdata + usernmlen + 1, md5string,
201
- sizeof(md5string));
266
+ cbsasl_hmac_md5((unsigned char *)serverin, serverinlen, pass->data, pass->len, digest);
267
+ cbsasl_hex_encode(md5string, (char *)digest, DIGEST_LENGTH);
268
+ memcpy(conn->c.client.userdata, usernm, usernmlen);
269
+ conn->c.client.userdata[usernmlen] = ' ';
270
+ memcpy(conn->c.client.userdata + usernmlen + 1, md5string, sizeof(md5string));
271
+ break;
272
+ }
273
+ case SASL_AUTH_MECH_SCRAM_SHA1:
274
+ case SASL_AUTH_MECH_SCRAM_SHA256:
275
+ case SASL_AUTH_MECH_SCRAM_SHA512: {
276
+ if (!conn->c.client.auth_message) {
277
+ const char *combinednonce = NULL; // nonce extracted from server's first reply
278
+ unsigned int noncelen = 0;
279
+ const char *salt = NULL; // salt extracted from server's first reply
280
+ unsigned int saltlen = 0;
281
+ unsigned int itcount = 0;
282
+ unsigned char saltedpassword[CBSASL_SHA512_DIGEST_SIZE]; // max digest size
283
+ unsigned int saltedpasslen = 0;
284
+ unsigned int prooflen = 0; // proof size in base64
202
285
 
286
+ ret =
287
+ parse_server_challenge(serverin, serverinlen, &combinednonce, &noncelen, &salt, &saltlen, &itcount);
288
+ if (ret != SASL_OK) {
289
+ return ret;
290
+ }
291
+ if (!combinednonce || !noncelen || !salt || !saltlen || !itcount) {
292
+ // missing or invalid value in server challenge
293
+ return SASL_BADPARAM;
294
+ }
295
+ if (noncelen < SCRAM_NONCE_SIZE * 2 ||
296
+ memcmp(combinednonce, conn->c.client.nonce, SCRAM_NONCE_SIZE * 2)) {
297
+ // the combined nonce doesn't start with the client nonce we sent previously
298
+ return SASL_BADPARAM;
299
+ }
300
+ // ok, now we can compute the client proof
301
+ ret = generate_salted_password(conn->c.client.auth_mech, pass, salt, saltlen, itcount, saltedpassword,
302
+ &saltedpasslen);
303
+ if (ret != SASL_OK) {
304
+ return ret;
305
+ }
306
+ // save salted password for later use
307
+ conn->c.client.saltedpassword = calloc(saltedpasslen, 1);
308
+ if (conn->c.client.saltedpassword == NULL) {
309
+ return SASL_NOMEM;
310
+ }
311
+ memcpy(conn->c.client.saltedpassword, saltedpassword, saltedpasslen);
312
+ conn->c.client.saltedpasslen = saltedpasslen;
313
+
314
+ // before building the client proof, we start building the client final message,
315
+ // as it is used for the computation of the proof
316
+ // The final message starts with the base64-encoded GS2 header from the initial message.
317
+ // As we always use "n,,", we can hardcode directly its base64-counterpart, so "biws".
318
+ #define FINAL_HEADER "c=biws,r="
319
+ #define PROOF_ATTR ",p="
320
+ switch (conn->c.client.auth_mech) {
321
+ case SASL_AUTH_MECH_SCRAM_SHA1:
322
+ prooflen = (CBSASL_SHA1_DIGEST_SIZE / 3 + 1) * 4;
323
+ break;
324
+ case SASL_AUTH_MECH_SCRAM_SHA256:
325
+ prooflen = (CBSASL_SHA256_DIGEST_SIZE / 3 + 1) * 4;
326
+ break;
327
+ case SASL_AUTH_MECH_SCRAM_SHA512:
328
+ prooflen = (CBSASL_SHA512_DIGEST_SIZE / 3 + 1) * 4;
329
+ break;
330
+ default:
331
+ break;
332
+ }
333
+ conn->c.client.userdata =
334
+ calloc(strlen(FINAL_HEADER) + noncelen + strlen(PROOF_ATTR) + prooflen + 1, 1);
335
+ if (conn->c.client.userdata == NULL) {
336
+ return SASL_NOMEM;
337
+ }
338
+ memcpy(conn->c.client.userdata, FINAL_HEADER, strlen(FINAL_HEADER));
339
+ memcpy(conn->c.client.userdata + strlen(FINAL_HEADER), combinednonce, noncelen);
340
+ memcpy(conn->c.client.userdata + strlen(FINAL_HEADER) + noncelen, PROOF_ATTR, strlen(PROOF_ATTR));
341
+
342
+ ret = compute_client_proof(
343
+ conn->c.client.auth_mech, saltedpassword, saltedpasslen, conn->c.client.client_first_message_bare,
344
+ strlen(conn->c.client.client_first_message_bare), serverin, serverinlen, conn->c.client.userdata,
345
+ strlen(FINAL_HEADER) + noncelen, &(conn->c.client.auth_message),
346
+ conn->c.client.userdata + strlen(FINAL_HEADER) + noncelen + strlen(PROOF_ATTR), prooflen + 1);
347
+ if (ret != SASL_OK) {
348
+ return ret;
349
+ }
350
+ } else {
351
+ // auth_message should not be already set
352
+ return SASL_FAIL;
353
+ }
354
+ break;
355
+ }
356
+ default:
357
+ break;
358
+ }
203
359
  *clientout = conn->c.client.userdata;
204
360
  *clientoutlen = strlen(conn->c.client.userdata);
205
361
 
206
362
  return SASL_CONTINUE;
207
363
  }
364
+
365
+ cbsasl_error_t cbsasl_client_check(cbsasl_conn_t *conn, const char *serverin, unsigned int serverinlen)
366
+ {
367
+ switch (conn->c.client.auth_mech) {
368
+ case SASL_AUTH_MECH_SCRAM_SHA1:
369
+ case SASL_AUTH_MECH_SCRAM_SHA256:
370
+ case SASL_AUTH_MECH_SCRAM_SHA512: {
371
+ if (conn->c.client.auth_message) {
372
+ char serversign[(CBSASL_SHA512_DIGEST_SIZE / 3 + 1) * 4 + 1]; // max sign len
373
+ unsigned int serversignlen = 0;
374
+ cbsasl_error_t ret;
375
+
376
+ // Last step: we have to verify the server's proof.
377
+ // In case of positive answer from the server, its final reply must start with "v=".
378
+ if (serverinlen <= 2 || memcmp(serverin, "v=", 2)) {
379
+ return SASL_FAIL;
380
+ }
381
+ switch (conn->c.client.auth_mech) {
382
+ case SASL_AUTH_MECH_SCRAM_SHA1:
383
+ serversignlen = (CBSASL_SHA1_DIGEST_SIZE / 3 + 1) * 4;
384
+ break;
385
+ case SASL_AUTH_MECH_SCRAM_SHA256:
386
+ serversignlen = (CBSASL_SHA256_DIGEST_SIZE / 3 + 1) * 4;
387
+ break;
388
+ case SASL_AUTH_MECH_SCRAM_SHA512:
389
+ serversignlen = (CBSASL_SHA512_DIGEST_SIZE / 3 + 1) * 4;
390
+ break;
391
+ default:
392
+ break;
393
+ }
394
+ ret = compute_server_signature(conn->c.client.auth_mech, conn->c.client.saltedpassword,
395
+ conn->c.client.saltedpasslen, conn->c.client.auth_message, serversign,
396
+ sizeof(serversign));
397
+ if (ret != SASL_OK) {
398
+ return ret;
399
+ }
400
+
401
+ // ok, we can now compare the two values
402
+ if ((serverinlen - 2 < serversignlen) || (memcmp(serverin + 2, serversign, serversignlen))) {
403
+ return SASL_FAIL;
404
+ }
405
+ } else {
406
+ // we have an issue: auth_message should not have been cleared
407
+ return SASL_FAIL;
408
+ }
409
+ break;
410
+ }
411
+ case SASL_AUTH_MECH_CRAM_MD5:
412
+ case SASL_AUTH_MECH_PLAIN:
413
+ default:
414
+ // nothing to do
415
+ break;
416
+ }
417
+
418
+ return SASL_OK;
419
+ }