libcouchbase 1.2.8 → 1.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (186) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +4 -4
  3. data/README.md +16 -8
  4. data/ext/libcouchbase/CMakeLists.txt +34 -32
  5. data/ext/libcouchbase/RELEASE_NOTES.markdown +277 -6
  6. data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +14 -0
  7. data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibevent.cmake +2 -0
  8. data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibuv.cmake +2 -1
  9. data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
  10. data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +8 -1
  11. data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
  12. data/ext/libcouchbase/cmake/config-cmake.h.in +14 -0
  13. data/ext/libcouchbase/cmake/configure +8 -26
  14. data/ext/libcouchbase/cmake/defs.mk.in +2 -2
  15. data/ext/libcouchbase/cmake/libcouchbase.stp.in +829 -0
  16. data/ext/libcouchbase/cmake/source_files.cmake +11 -2
  17. data/ext/libcouchbase/contrib/cbsasl/CMakeLists.txt +18 -2
  18. data/ext/libcouchbase/contrib/cbsasl/include/cbsasl/cbsasl.h +44 -2
  19. data/ext/libcouchbase/contrib/cbsasl/src/client.c +285 -73
  20. data/ext/libcouchbase/contrib/cbsasl/src/common.c +4 -0
  21. data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.c +500 -0
  22. data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.h +99 -0
  23. data/ext/libcouchbase/contrib/cliopts/CMakeLists.txt +1 -1
  24. data/ext/libcouchbase/contrib/cliopts/cliopts.h +14 -1
  25. data/ext/libcouchbase/contrib/snappy/CMakeLists.txt +2 -3
  26. data/ext/libcouchbase/contrib/snappy/snappy-sinksource.cc +4 -0
  27. data/ext/libcouchbase/contrib/snappy/snappy-stubs-public.h +7 -5
  28. data/ext/libcouchbase/contrib/snappy/snappy.cc +7 -2
  29. data/ext/libcouchbase/example/crypto/.gitignore +2 -0
  30. data/ext/libcouchbase/example/crypto/Makefile +13 -0
  31. data/ext/libcouchbase/example/crypto/common_provider.c +24 -0
  32. data/ext/libcouchbase/example/crypto/common_provider.h +31 -0
  33. data/ext/libcouchbase/example/crypto/openssl_symmetric_decrypt.c +139 -0
  34. data/ext/libcouchbase/example/crypto/openssl_symmetric_encrypt.c +147 -0
  35. data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.c +281 -0
  36. data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.h +29 -0
  37. data/ext/libcouchbase/example/tracing/.gitignore +2 -0
  38. data/ext/libcouchbase/example/tracing/Makefile +8 -0
  39. data/ext/libcouchbase/example/tracing/cJSON.c +1 -0
  40. data/ext/libcouchbase/example/tracing/cJSON.h +1 -0
  41. data/ext/libcouchbase/example/tracing/tracing.c +439 -0
  42. data/ext/libcouchbase/example/tracing/views.c +444 -0
  43. data/ext/libcouchbase/include/libcouchbase/auth.h +56 -4
  44. data/ext/libcouchbase/include/libcouchbase/cbft.h +8 -0
  45. data/ext/libcouchbase/include/libcouchbase/cntl-private.h +55 -1
  46. data/ext/libcouchbase/include/libcouchbase/cntl.h +101 -1
  47. data/ext/libcouchbase/include/libcouchbase/configuration.h.in +6 -0
  48. data/ext/libcouchbase/include/libcouchbase/couchbase.h +109 -6
  49. data/ext/libcouchbase/include/libcouchbase/crypto.h +140 -0
  50. data/ext/libcouchbase/include/libcouchbase/error.h +38 -2
  51. data/ext/libcouchbase/include/libcouchbase/kvbuf.h +6 -1
  52. data/ext/libcouchbase/include/libcouchbase/metrics.h +79 -0
  53. data/ext/libcouchbase/include/libcouchbase/n1ql.h +9 -0
  54. data/ext/libcouchbase/include/libcouchbase/tracing.h +319 -0
  55. data/ext/libcouchbase/include/libcouchbase/vbucket.h +1 -1
  56. data/ext/libcouchbase/include/libcouchbase/views.h +8 -0
  57. data/ext/libcouchbase/include/memcached/protocol_binary.h +40 -10
  58. data/ext/libcouchbase/packaging/rpm/libcouchbase.spec.in +6 -14
  59. data/ext/libcouchbase/plugins/io/libuv/plugin-internal.h +3 -0
  60. data/ext/libcouchbase/plugins/io/libuv/plugin-libuv.c +1 -0
  61. data/ext/libcouchbase/plugins/io/select/plugin-select.c +4 -1
  62. data/ext/libcouchbase/src/auth-priv.h +36 -4
  63. data/ext/libcouchbase/src/auth.cc +66 -27
  64. data/ext/libcouchbase/src/bootstrap.cc +1 -1
  65. data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +12 -7
  66. data/ext/libcouchbase/src/bucketconfig/bc_http.cc +26 -17
  67. data/ext/libcouchbase/src/bucketconfig/bc_http.h +1 -1
  68. data/ext/libcouchbase/src/bucketconfig/clconfig.h +4 -2
  69. data/ext/libcouchbase/src/bucketconfig/confmon.cc +6 -3
  70. data/ext/libcouchbase/src/cbft.cc +48 -0
  71. data/ext/libcouchbase/src/cntl.cc +138 -2
  72. data/ext/libcouchbase/src/config_static.h +17 -0
  73. data/ext/libcouchbase/src/connspec.cc +54 -6
  74. data/ext/libcouchbase/src/connspec.h +9 -1
  75. data/ext/libcouchbase/src/crypto.cc +386 -0
  76. data/ext/libcouchbase/src/ctx-log-inl.h +23 -6
  77. data/ext/libcouchbase/src/dump.cc +4 -0
  78. data/ext/libcouchbase/src/getconfig.cc +1 -2
  79. data/ext/libcouchbase/src/handler.cc +65 -27
  80. data/ext/libcouchbase/src/hostlist.cc +35 -7
  81. data/ext/libcouchbase/src/hostlist.h +7 -0
  82. data/ext/libcouchbase/src/http/http-priv.h +2 -0
  83. data/ext/libcouchbase/src/http/http.cc +77 -37
  84. data/ext/libcouchbase/src/http/http_io.cc +19 -2
  85. data/ext/libcouchbase/src/instance.cc +90 -17
  86. data/ext/libcouchbase/src/internal.h +5 -0
  87. data/ext/libcouchbase/src/lcbio/connect.cc +39 -4
  88. data/ext/libcouchbase/src/lcbio/connect.h +27 -0
  89. data/ext/libcouchbase/src/lcbio/ctx.c +49 -23
  90. data/ext/libcouchbase/src/lcbio/ioutils.cc +30 -3
  91. data/ext/libcouchbase/src/lcbio/ioutils.h +2 -0
  92. data/ext/libcouchbase/src/lcbio/manager.cc +44 -8
  93. data/ext/libcouchbase/src/lcbio/manager.h +2 -0
  94. data/ext/libcouchbase/src/lcbio/rw-inl.h +1 -0
  95. data/ext/libcouchbase/src/lcbio/ssl.h +3 -5
  96. data/ext/libcouchbase/src/logging.c +1 -1
  97. data/ext/libcouchbase/src/logging.h +2 -0
  98. data/ext/libcouchbase/src/mc/compress.cc +164 -0
  99. data/ext/libcouchbase/src/mc/compress.h +7 -12
  100. data/ext/libcouchbase/src/mc/mcreq-flush-inl.h +5 -1
  101. data/ext/libcouchbase/src/mc/mcreq.c +11 -1
  102. data/ext/libcouchbase/src/mc/mcreq.h +35 -4
  103. data/ext/libcouchbase/src/mcserver/mcserver.cc +30 -7
  104. data/ext/libcouchbase/src/mcserver/mcserver.h +7 -0
  105. data/ext/libcouchbase/src/mcserver/negotiate.cc +103 -57
  106. data/ext/libcouchbase/src/mcserver/negotiate.h +2 -2
  107. data/ext/libcouchbase/src/mctx-helper.h +11 -0
  108. data/ext/libcouchbase/src/metrics.cc +132 -0
  109. data/ext/libcouchbase/src/n1ql/ixmgmt.cc +2 -1
  110. data/ext/libcouchbase/src/n1ql/n1ql.cc +66 -0
  111. data/ext/libcouchbase/src/newconfig.cc +9 -2
  112. data/ext/libcouchbase/src/operations/counter.cc +2 -1
  113. data/ext/libcouchbase/src/operations/durability-cas.cc +11 -0
  114. data/ext/libcouchbase/src/operations/durability-seqno.cc +3 -0
  115. data/ext/libcouchbase/src/operations/durability.cc +24 -2
  116. data/ext/libcouchbase/src/operations/durability_internal.h +19 -0
  117. data/ext/libcouchbase/src/operations/get.cc +4 -2
  118. data/ext/libcouchbase/src/operations/observe-seqno.cc +1 -0
  119. data/ext/libcouchbase/src/operations/observe.cc +113 -62
  120. data/ext/libcouchbase/src/operations/ping.cc +246 -67
  121. data/ext/libcouchbase/src/operations/remove.cc +2 -1
  122. data/ext/libcouchbase/src/operations/store.cc +17 -14
  123. data/ext/libcouchbase/src/operations/touch.cc +3 -0
  124. data/ext/libcouchbase/src/packetutils.h +68 -4
  125. data/ext/libcouchbase/src/probes.d +132 -161
  126. data/ext/libcouchbase/src/rdb/bigalloc.c +1 -1
  127. data/ext/libcouchbase/src/retryq.cc +6 -2
  128. data/ext/libcouchbase/src/rnd.cc +68 -0
  129. data/ext/libcouchbase/src/rnd.h +39 -0
  130. data/ext/libcouchbase/src/settings.c +27 -0
  131. data/ext/libcouchbase/src/settings.h +67 -3
  132. data/ext/libcouchbase/src/ssl/CMakeLists.txt +0 -12
  133. data/ext/libcouchbase/src/ssl/ssl_common.c +23 -4
  134. data/ext/libcouchbase/src/strcodecs/base64.c +141 -16
  135. data/ext/libcouchbase/src/strcodecs/strcodecs.h +16 -1
  136. data/ext/libcouchbase/src/trace.h +68 -61
  137. data/ext/libcouchbase/src/tracing/span.cc +289 -0
  138. data/ext/libcouchbase/src/tracing/threshold_logging_tracer.cc +171 -0
  139. data/ext/libcouchbase/src/tracing/tracer.cc +53 -0
  140. data/ext/libcouchbase/src/tracing/tracing-internal.h +213 -0
  141. data/ext/libcouchbase/src/utilities.c +5 -0
  142. data/ext/libcouchbase/src/vbucket/CMakeLists.txt +2 -2
  143. data/ext/libcouchbase/src/vbucket/vbucket.c +50 -18
  144. data/ext/libcouchbase/src/views/docreq.cc +26 -1
  145. data/ext/libcouchbase/src/views/docreq.h +17 -0
  146. data/ext/libcouchbase/src/views/viewreq.cc +64 -1
  147. data/ext/libcouchbase/src/views/viewreq.h +21 -0
  148. data/ext/libcouchbase/tests/CMakeLists.txt +6 -6
  149. data/ext/libcouchbase/tests/basic/t_base64.cc +34 -6
  150. data/ext/libcouchbase/tests/basic/t_connstr.cc +14 -0
  151. data/ext/libcouchbase/tests/basic/t_creds.cc +10 -10
  152. data/ext/libcouchbase/tests/basic/t_host.cc +22 -2
  153. data/ext/libcouchbase/tests/basic/t_scram.cc +514 -0
  154. data/ext/libcouchbase/tests/check-all.cc +6 -2
  155. data/ext/libcouchbase/tests/iotests/mock-environment.cc +64 -0
  156. data/ext/libcouchbase/tests/iotests/mock-environment.h +27 -1
  157. data/ext/libcouchbase/tests/iotests/t_confmon.cc +2 -2
  158. data/ext/libcouchbase/tests/iotests/t_forward.cc +8 -0
  159. data/ext/libcouchbase/tests/iotests/t_netfail.cc +124 -0
  160. data/ext/libcouchbase/tests/iotests/t_smoke.cc +1 -1
  161. data/ext/libcouchbase/tests/iotests/t_snappy.cc +316 -0
  162. data/ext/libcouchbase/tests/socktests/socktest.cc +2 -2
  163. data/ext/libcouchbase/tests/socktests/t_basic.cc +6 -6
  164. data/ext/libcouchbase/tests/socktests/t_manager.cc +1 -1
  165. data/ext/libcouchbase/tests/socktests/t_ssl.cc +1 -1
  166. data/ext/libcouchbase/tools/CMakeLists.txt +1 -1
  167. data/ext/libcouchbase/tools/cbc-handlers.h +17 -0
  168. data/ext/libcouchbase/tools/cbc-n1qlback.cc +7 -4
  169. data/ext/libcouchbase/tools/cbc-pillowfight.cc +408 -100
  170. data/ext/libcouchbase/tools/cbc-proxy.cc +134 -3
  171. data/ext/libcouchbase/tools/cbc-subdoc.cc +1 -2
  172. data/ext/libcouchbase/tools/cbc.cc +113 -8
  173. data/ext/libcouchbase/tools/common/histogram.cc +1 -0
  174. data/ext/libcouchbase/tools/common/options.cc +28 -1
  175. data/ext/libcouchbase/tools/common/options.h +5 -0
  176. data/ext/libcouchbase/tools/docgen/docgen.h +36 -10
  177. data/ext/libcouchbase/tools/docgen/loc.h +5 -4
  178. data/ext/libcouchbase/tools/docgen/seqgen.h +28 -0
  179. data/lib/libcouchbase/ext/libcouchbase/enums.rb +10 -0
  180. data/lib/libcouchbase/n1ql.rb +6 -1
  181. data/lib/libcouchbase/version.rb +1 -1
  182. data/spec/connection_spec.rb +6 -6
  183. metadata +38 -5
  184. data/ext/libcouchbase/cmake/Modules/FindCouchbaseSnappy.cmake +0 -11
  185. data/ext/libcouchbase/src/mc/compress.c +0 -90
  186. data/ext/libcouchbase/tools/common/my_inttypes.h +0 -22
@@ -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
+ }