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.
- checksums.yaml +4 -4
- data/.travis.yml +4 -4
- data/README.md +16 -8
- data/ext/libcouchbase/CMakeLists.txt +34 -32
- data/ext/libcouchbase/RELEASE_NOTES.markdown +277 -6
- data/ext/libcouchbase/cmake/Modules/ConfigureDtrace.cmake +14 -0
- data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibevent.cmake +2 -0
- data/ext/libcouchbase/cmake/Modules/FindCouchbaseLibuv.cmake +2 -1
- data/ext/libcouchbase/cmake/Modules/GenerateConfigDotH.cmake +2 -0
- data/ext/libcouchbase/cmake/Modules/GetLibcouchbaseFlags.cmake +8 -1
- data/ext/libcouchbase/cmake/Modules/GetVersionInfo.cmake +3 -3
- data/ext/libcouchbase/cmake/config-cmake.h.in +14 -0
- data/ext/libcouchbase/cmake/configure +8 -26
- data/ext/libcouchbase/cmake/defs.mk.in +2 -2
- data/ext/libcouchbase/cmake/libcouchbase.stp.in +829 -0
- data/ext/libcouchbase/cmake/source_files.cmake +11 -2
- data/ext/libcouchbase/contrib/cbsasl/CMakeLists.txt +18 -2
- data/ext/libcouchbase/contrib/cbsasl/include/cbsasl/cbsasl.h +44 -2
- data/ext/libcouchbase/contrib/cbsasl/src/client.c +285 -73
- data/ext/libcouchbase/contrib/cbsasl/src/common.c +4 -0
- data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.c +500 -0
- data/ext/libcouchbase/contrib/cbsasl/src/scram-sha/scram_utils.h +99 -0
- data/ext/libcouchbase/contrib/cliopts/CMakeLists.txt +1 -1
- data/ext/libcouchbase/contrib/cliopts/cliopts.h +14 -1
- data/ext/libcouchbase/contrib/snappy/CMakeLists.txt +2 -3
- data/ext/libcouchbase/contrib/snappy/snappy-sinksource.cc +4 -0
- data/ext/libcouchbase/contrib/snappy/snappy-stubs-public.h +7 -5
- data/ext/libcouchbase/contrib/snappy/snappy.cc +7 -2
- data/ext/libcouchbase/example/crypto/.gitignore +2 -0
- data/ext/libcouchbase/example/crypto/Makefile +13 -0
- data/ext/libcouchbase/example/crypto/common_provider.c +24 -0
- data/ext/libcouchbase/example/crypto/common_provider.h +31 -0
- data/ext/libcouchbase/example/crypto/openssl_symmetric_decrypt.c +139 -0
- data/ext/libcouchbase/example/crypto/openssl_symmetric_encrypt.c +147 -0
- data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.c +281 -0
- data/ext/libcouchbase/example/crypto/openssl_symmetric_provider.h +29 -0
- data/ext/libcouchbase/example/tracing/.gitignore +2 -0
- data/ext/libcouchbase/example/tracing/Makefile +8 -0
- data/ext/libcouchbase/example/tracing/cJSON.c +1 -0
- data/ext/libcouchbase/example/tracing/cJSON.h +1 -0
- data/ext/libcouchbase/example/tracing/tracing.c +439 -0
- data/ext/libcouchbase/example/tracing/views.c +444 -0
- data/ext/libcouchbase/include/libcouchbase/auth.h +56 -4
- data/ext/libcouchbase/include/libcouchbase/cbft.h +8 -0
- data/ext/libcouchbase/include/libcouchbase/cntl-private.h +55 -1
- data/ext/libcouchbase/include/libcouchbase/cntl.h +101 -1
- data/ext/libcouchbase/include/libcouchbase/configuration.h.in +6 -0
- data/ext/libcouchbase/include/libcouchbase/couchbase.h +109 -6
- data/ext/libcouchbase/include/libcouchbase/crypto.h +140 -0
- data/ext/libcouchbase/include/libcouchbase/error.h +38 -2
- data/ext/libcouchbase/include/libcouchbase/kvbuf.h +6 -1
- data/ext/libcouchbase/include/libcouchbase/metrics.h +79 -0
- data/ext/libcouchbase/include/libcouchbase/n1ql.h +9 -0
- data/ext/libcouchbase/include/libcouchbase/tracing.h +319 -0
- data/ext/libcouchbase/include/libcouchbase/vbucket.h +1 -1
- data/ext/libcouchbase/include/libcouchbase/views.h +8 -0
- data/ext/libcouchbase/include/memcached/protocol_binary.h +40 -10
- data/ext/libcouchbase/packaging/rpm/libcouchbase.spec.in +6 -14
- data/ext/libcouchbase/plugins/io/libuv/plugin-internal.h +3 -0
- data/ext/libcouchbase/plugins/io/libuv/plugin-libuv.c +1 -0
- data/ext/libcouchbase/plugins/io/select/plugin-select.c +4 -1
- data/ext/libcouchbase/src/auth-priv.h +36 -4
- data/ext/libcouchbase/src/auth.cc +66 -27
- data/ext/libcouchbase/src/bootstrap.cc +1 -1
- data/ext/libcouchbase/src/bucketconfig/bc_cccp.cc +12 -7
- data/ext/libcouchbase/src/bucketconfig/bc_http.cc +26 -17
- data/ext/libcouchbase/src/bucketconfig/bc_http.h +1 -1
- data/ext/libcouchbase/src/bucketconfig/clconfig.h +4 -2
- data/ext/libcouchbase/src/bucketconfig/confmon.cc +6 -3
- data/ext/libcouchbase/src/cbft.cc +48 -0
- data/ext/libcouchbase/src/cntl.cc +138 -2
- data/ext/libcouchbase/src/config_static.h +17 -0
- data/ext/libcouchbase/src/connspec.cc +54 -6
- data/ext/libcouchbase/src/connspec.h +9 -1
- data/ext/libcouchbase/src/crypto.cc +386 -0
- data/ext/libcouchbase/src/ctx-log-inl.h +23 -6
- data/ext/libcouchbase/src/dump.cc +4 -0
- data/ext/libcouchbase/src/getconfig.cc +1 -2
- data/ext/libcouchbase/src/handler.cc +65 -27
- data/ext/libcouchbase/src/hostlist.cc +35 -7
- data/ext/libcouchbase/src/hostlist.h +7 -0
- data/ext/libcouchbase/src/http/http-priv.h +2 -0
- data/ext/libcouchbase/src/http/http.cc +77 -37
- data/ext/libcouchbase/src/http/http_io.cc +19 -2
- data/ext/libcouchbase/src/instance.cc +90 -17
- data/ext/libcouchbase/src/internal.h +5 -0
- data/ext/libcouchbase/src/lcbio/connect.cc +39 -4
- data/ext/libcouchbase/src/lcbio/connect.h +27 -0
- data/ext/libcouchbase/src/lcbio/ctx.c +49 -23
- data/ext/libcouchbase/src/lcbio/ioutils.cc +30 -3
- data/ext/libcouchbase/src/lcbio/ioutils.h +2 -0
- data/ext/libcouchbase/src/lcbio/manager.cc +44 -8
- data/ext/libcouchbase/src/lcbio/manager.h +2 -0
- data/ext/libcouchbase/src/lcbio/rw-inl.h +1 -0
- data/ext/libcouchbase/src/lcbio/ssl.h +3 -5
- data/ext/libcouchbase/src/logging.c +1 -1
- data/ext/libcouchbase/src/logging.h +2 -0
- data/ext/libcouchbase/src/mc/compress.cc +164 -0
- data/ext/libcouchbase/src/mc/compress.h +7 -12
- data/ext/libcouchbase/src/mc/mcreq-flush-inl.h +5 -1
- data/ext/libcouchbase/src/mc/mcreq.c +11 -1
- data/ext/libcouchbase/src/mc/mcreq.h +35 -4
- data/ext/libcouchbase/src/mcserver/mcserver.cc +30 -7
- data/ext/libcouchbase/src/mcserver/mcserver.h +7 -0
- data/ext/libcouchbase/src/mcserver/negotiate.cc +103 -57
- data/ext/libcouchbase/src/mcserver/negotiate.h +2 -2
- data/ext/libcouchbase/src/mctx-helper.h +11 -0
- data/ext/libcouchbase/src/metrics.cc +132 -0
- data/ext/libcouchbase/src/n1ql/ixmgmt.cc +2 -1
- data/ext/libcouchbase/src/n1ql/n1ql.cc +66 -0
- data/ext/libcouchbase/src/newconfig.cc +9 -2
- data/ext/libcouchbase/src/operations/counter.cc +2 -1
- data/ext/libcouchbase/src/operations/durability-cas.cc +11 -0
- data/ext/libcouchbase/src/operations/durability-seqno.cc +3 -0
- data/ext/libcouchbase/src/operations/durability.cc +24 -2
- data/ext/libcouchbase/src/operations/durability_internal.h +19 -0
- data/ext/libcouchbase/src/operations/get.cc +4 -2
- data/ext/libcouchbase/src/operations/observe-seqno.cc +1 -0
- data/ext/libcouchbase/src/operations/observe.cc +113 -62
- data/ext/libcouchbase/src/operations/ping.cc +246 -67
- data/ext/libcouchbase/src/operations/remove.cc +2 -1
- data/ext/libcouchbase/src/operations/store.cc +17 -14
- data/ext/libcouchbase/src/operations/touch.cc +3 -0
- data/ext/libcouchbase/src/packetutils.h +68 -4
- data/ext/libcouchbase/src/probes.d +132 -161
- data/ext/libcouchbase/src/rdb/bigalloc.c +1 -1
- data/ext/libcouchbase/src/retryq.cc +6 -2
- data/ext/libcouchbase/src/rnd.cc +68 -0
- data/ext/libcouchbase/src/rnd.h +39 -0
- data/ext/libcouchbase/src/settings.c +27 -0
- data/ext/libcouchbase/src/settings.h +67 -3
- data/ext/libcouchbase/src/ssl/CMakeLists.txt +0 -12
- data/ext/libcouchbase/src/ssl/ssl_common.c +23 -4
- data/ext/libcouchbase/src/strcodecs/base64.c +141 -16
- data/ext/libcouchbase/src/strcodecs/strcodecs.h +16 -1
- data/ext/libcouchbase/src/trace.h +68 -61
- data/ext/libcouchbase/src/tracing/span.cc +289 -0
- data/ext/libcouchbase/src/tracing/threshold_logging_tracer.cc +171 -0
- data/ext/libcouchbase/src/tracing/tracer.cc +53 -0
- data/ext/libcouchbase/src/tracing/tracing-internal.h +213 -0
- data/ext/libcouchbase/src/utilities.c +5 -0
- data/ext/libcouchbase/src/vbucket/CMakeLists.txt +2 -2
- data/ext/libcouchbase/src/vbucket/vbucket.c +50 -18
- data/ext/libcouchbase/src/views/docreq.cc +26 -1
- data/ext/libcouchbase/src/views/docreq.h +17 -0
- data/ext/libcouchbase/src/views/viewreq.cc +64 -1
- data/ext/libcouchbase/src/views/viewreq.h +21 -0
- data/ext/libcouchbase/tests/CMakeLists.txt +6 -6
- data/ext/libcouchbase/tests/basic/t_base64.cc +34 -6
- data/ext/libcouchbase/tests/basic/t_connstr.cc +14 -0
- data/ext/libcouchbase/tests/basic/t_creds.cc +10 -10
- data/ext/libcouchbase/tests/basic/t_host.cc +22 -2
- data/ext/libcouchbase/tests/basic/t_scram.cc +514 -0
- data/ext/libcouchbase/tests/check-all.cc +6 -2
- data/ext/libcouchbase/tests/iotests/mock-environment.cc +64 -0
- data/ext/libcouchbase/tests/iotests/mock-environment.h +27 -1
- data/ext/libcouchbase/tests/iotests/t_confmon.cc +2 -2
- data/ext/libcouchbase/tests/iotests/t_forward.cc +8 -0
- data/ext/libcouchbase/tests/iotests/t_netfail.cc +124 -0
- data/ext/libcouchbase/tests/iotests/t_smoke.cc +1 -1
- data/ext/libcouchbase/tests/iotests/t_snappy.cc +316 -0
- data/ext/libcouchbase/tests/socktests/socktest.cc +2 -2
- data/ext/libcouchbase/tests/socktests/t_basic.cc +6 -6
- data/ext/libcouchbase/tests/socktests/t_manager.cc +1 -1
- data/ext/libcouchbase/tests/socktests/t_ssl.cc +1 -1
- data/ext/libcouchbase/tools/CMakeLists.txt +1 -1
- data/ext/libcouchbase/tools/cbc-handlers.h +17 -0
- data/ext/libcouchbase/tools/cbc-n1qlback.cc +7 -4
- data/ext/libcouchbase/tools/cbc-pillowfight.cc +408 -100
- data/ext/libcouchbase/tools/cbc-proxy.cc +134 -3
- data/ext/libcouchbase/tools/cbc-subdoc.cc +1 -2
- data/ext/libcouchbase/tools/cbc.cc +113 -8
- data/ext/libcouchbase/tools/common/histogram.cc +1 -0
- data/ext/libcouchbase/tools/common/options.cc +28 -1
- data/ext/libcouchbase/tools/common/options.h +5 -0
- data/ext/libcouchbase/tools/docgen/docgen.h +36 -10
- data/ext/libcouchbase/tools/docgen/loc.h +5 -4
- data/ext/libcouchbase/tools/docgen/seqgen.h +28 -0
- data/lib/libcouchbase/ext/libcouchbase/enums.rb +10 -0
- data/lib/libcouchbase/n1ql.rb +6 -1
- data/lib/libcouchbase/version.rb +1 -1
- data/spec/connection_spec.rb +6 -6
- metadata +38 -5
- data/ext/libcouchbase/cmake/Modules/FindCouchbaseSnappy.cmake +0 -11
- data/ext/libcouchbase/src/mc/compress.c +0 -90
- data/ext/libcouchbase/tools/common/my_inttypes.h +0 -22
|
@@ -66,7 +66,7 @@ Connspec::parse_hosts(const char *hostbegin,
|
|
|
66
66
|
while (*c) {
|
|
67
67
|
// get the current host
|
|
68
68
|
const char *curend;
|
|
69
|
-
unsigned curlen, hostlen;
|
|
69
|
+
unsigned curlen, hostlen, hoststart;
|
|
70
70
|
int rv;
|
|
71
71
|
|
|
72
72
|
/* Seek ahead, chopping off any ',' */
|
|
@@ -95,15 +95,30 @@ Connspec::parse_hosts(const char *hostbegin,
|
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
size_t colonpos = scratch.find(":");
|
|
98
|
+
size_t rcolonpos = scratch.rfind(":");
|
|
98
99
|
std::string port;
|
|
99
100
|
|
|
101
|
+
hoststart = 0;
|
|
100
102
|
if (colonpos == std::string::npos) {
|
|
101
103
|
hostlen = scratch.size();
|
|
102
|
-
} else if (colonpos ==
|
|
103
|
-
|
|
104
|
+
} else if (colonpos == rcolonpos) {
|
|
105
|
+
if (colonpos == 0 || colonpos == scratch.size() - 1) {
|
|
106
|
+
SET_ERROR("First or last character in spec is colon!");
|
|
107
|
+
} else {
|
|
108
|
+
hostlen = colonpos;
|
|
109
|
+
port = scratch.substr(colonpos + 1);
|
|
110
|
+
}
|
|
104
111
|
} else {
|
|
105
|
-
|
|
106
|
-
|
|
112
|
+
size_t rbracket = scratch.rfind(']');
|
|
113
|
+
if (scratch[0] == '[' && rbracket != std::string::npos) {
|
|
114
|
+
hoststart = 1;
|
|
115
|
+
hostlen = rbracket - hoststart;
|
|
116
|
+
if (scratch.size() > rbracket + 1) {
|
|
117
|
+
port = scratch.substr(rbracket + 2);
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
hostlen = scratch.size();
|
|
121
|
+
}
|
|
107
122
|
}
|
|
108
123
|
|
|
109
124
|
if (m_flags & F_DNSSRV_EXPLICIT) {
|
|
@@ -116,7 +131,7 @@ Connspec::parse_hosts(const char *hostbegin,
|
|
|
116
131
|
|
|
117
132
|
m_hosts.resize(m_hosts.size() + 1);
|
|
118
133
|
Spechost *dh = &m_hosts.back();
|
|
119
|
-
dh->hostname = scratch.substr(
|
|
134
|
+
dh->hostname = scratch.substr(hoststart, hostlen);
|
|
120
135
|
|
|
121
136
|
if (port.empty()) {
|
|
122
137
|
continue;
|
|
@@ -235,15 +250,35 @@ Connspec::parse_options(
|
|
|
235
250
|
} else {
|
|
236
251
|
SET_ERROR("Invalid value for 'ssl'. Choices are on, off, and no_verify");
|
|
237
252
|
}
|
|
253
|
+
} else if (!strcmp(key, "truststorepath")) {
|
|
254
|
+
if (! (m_flags & F_SSLSCHEME)) {
|
|
255
|
+
SET_ERROR("Trust store path must be specified with SSL host or scheme");
|
|
256
|
+
}
|
|
257
|
+
m_truststorepath = value;
|
|
238
258
|
} else if (!strcmp(key, "certpath")) {
|
|
239
259
|
if (! (m_flags & F_SSLSCHEME)) {
|
|
240
260
|
SET_ERROR("Certificate path must be specified with SSL host or scheme");
|
|
241
261
|
}
|
|
242
262
|
m_certpath = value;
|
|
263
|
+
} else if (!strcmp(key, "keypath")) {
|
|
264
|
+
if (! (m_flags & F_SSLSCHEME)) {
|
|
265
|
+
SET_ERROR("Private key path must be specified with SSL host or scheme");
|
|
266
|
+
}
|
|
267
|
+
m_keypath = value;
|
|
243
268
|
} else if (!strcmp(key, "console_log_level")) {
|
|
244
269
|
if (sscanf(value, "%d", &m_loglevel) != 1) {
|
|
245
270
|
SET_ERROR("console_log_level must be a numeric value");
|
|
246
271
|
}
|
|
272
|
+
} else if (!strcmp(key, "log_redaction")) {
|
|
273
|
+
int btmp = 0;
|
|
274
|
+
if (!strcmp(value, "on") || !strcmp(value, "true")) {
|
|
275
|
+
btmp = 1;
|
|
276
|
+
} else if (!strcmp(value, "off") || !strcmp(value, "false")) {
|
|
277
|
+
btmp = 0;
|
|
278
|
+
} else if (sscanf(value, "%d", &btmp) != 1) {
|
|
279
|
+
SET_ERROR("log_redaction must have numeric (boolean) value");
|
|
280
|
+
}
|
|
281
|
+
m_logredact = btmp != 0;
|
|
247
282
|
} else if (!strcmp(key, "dnssrv")) {
|
|
248
283
|
if ((m_flags & F_DNSSRV_EXPLICIT) == F_DNSSRV_EXPLICIT) {
|
|
249
284
|
SET_ERROR("Cannot use dnssrv scheme with dnssrv option");
|
|
@@ -261,10 +296,23 @@ Connspec::parse_options(
|
|
|
261
296
|
} else {
|
|
262
297
|
m_flags &= ~F_DNSSRV_EXPLICIT;
|
|
263
298
|
}
|
|
299
|
+
} else if (!strcmp(key, "ipv6")) {
|
|
300
|
+
if (!strcmp(value, "only")) {
|
|
301
|
+
m_ipv6 = LCB_IPV6_ONLY;
|
|
302
|
+
} else if (!strcmp(value, "disabled")) {
|
|
303
|
+
m_ipv6 = LCB_IPV6_DISABLED;
|
|
304
|
+
} else if (!strcmp(value, "allow")) {
|
|
305
|
+
m_ipv6 = LCB_IPV6_ALLOW;
|
|
306
|
+
} else {
|
|
307
|
+
SET_ERROR("Value for ipv6 must be 'disabled', 'allow', or 'only'");
|
|
308
|
+
}
|
|
264
309
|
} else {
|
|
265
310
|
m_ctlopts.push_back(std::make_pair(key, value));
|
|
266
311
|
}
|
|
267
312
|
}
|
|
313
|
+
if (!m_keypath.empty() && m_certpath.empty()) {
|
|
314
|
+
SET_ERROR("Private key path must be specified with certificate path");
|
|
315
|
+
}
|
|
268
316
|
|
|
269
317
|
return LCB_SUCCESS;
|
|
270
318
|
}
|
|
@@ -61,7 +61,7 @@ struct Spechost {
|
|
|
61
61
|
class LCB_CLASS_EXPORT Connspec {
|
|
62
62
|
public:
|
|
63
63
|
typedef std::vector<std::pair<std::string,std::string> > Options;
|
|
64
|
-
Connspec() : m_sslopts(0), m_implicit_port(0), m_loglevel(0), m_flags(0) {}
|
|
64
|
+
Connspec() : m_sslopts(0), m_implicit_port(0), m_loglevel(0), m_logredact(false), m_flags(0), m_ipv6(LCB_IPV6_DISABLED) {}
|
|
65
65
|
|
|
66
66
|
lcb_error_t parse(const char *connstr, const char **errmsg = NULL);
|
|
67
67
|
lcb_error_t load(const lcb_create_st&);
|
|
@@ -92,24 +92,31 @@ public:
|
|
|
92
92
|
const std::string& bucket() const { return m_bucket; }
|
|
93
93
|
const std::string& username() const { return m_username; }
|
|
94
94
|
const std::string& password() const { return m_password; }
|
|
95
|
+
const std::string& truststorepath() const { return m_truststorepath; }
|
|
95
96
|
const std::string& certpath() const { return m_certpath; }
|
|
97
|
+
const std::string& keypath() const { return m_keypath; }
|
|
96
98
|
unsigned sslopts() const { return m_sslopts; }
|
|
97
99
|
const Options& options() const { return m_ctlopts; }
|
|
98
100
|
unsigned loglevel() const { return m_loglevel; }
|
|
101
|
+
bool logredact() const { return m_logredact; }
|
|
99
102
|
const std::string& connstr() const { return m_connstr; }
|
|
100
103
|
void clear_hosts() { m_hosts.clear(); }
|
|
101
104
|
void add_host(const Spechost& host) { m_hosts.push_back(host); }
|
|
105
|
+
lcb_ipv6_t ipv6_policy() const { return m_ipv6; }
|
|
102
106
|
private:
|
|
103
107
|
Options m_ctlopts;
|
|
104
108
|
std::string m_bucket;
|
|
105
109
|
std::string m_username;
|
|
106
110
|
std::string m_password;
|
|
111
|
+
std::string m_truststorepath;
|
|
107
112
|
std::string m_certpath;
|
|
113
|
+
std::string m_keypath;
|
|
108
114
|
std::string m_connstr;
|
|
109
115
|
unsigned m_sslopts; /**< SSL Options */
|
|
110
116
|
std::vector<Spechost> m_hosts;
|
|
111
117
|
lcb_U16 m_implicit_port; /**< Implicit port, based on scheme */
|
|
112
118
|
int m_loglevel; /* cached loglevel */
|
|
119
|
+
bool m_logredact;
|
|
113
120
|
|
|
114
121
|
inline lcb_error_t parse_options(
|
|
115
122
|
const char *options, const char *optend, const char **errmsg);
|
|
@@ -118,6 +125,7 @@ private:
|
|
|
118
125
|
|
|
119
126
|
std::set<int> m_transports;
|
|
120
127
|
unsigned m_flags; /**< Internal flags */
|
|
128
|
+
lcb_ipv6_t m_ipv6;
|
|
121
129
|
};
|
|
122
130
|
|
|
123
131
|
#define LCB_SPECSCHEME_RAW "couchbase+explicit://"
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
|
2
|
+
/*
|
|
3
|
+
* Copyright 2017-2018 Couchbase, Inc.
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
#include "internal.h"
|
|
19
|
+
|
|
20
|
+
void lcbcrypto_ref(lcbcrypto_PROVIDER *provider)
|
|
21
|
+
{
|
|
22
|
+
provider->_refcnt++;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
void lcbcrypto_unref(lcbcrypto_PROVIDER *provider)
|
|
26
|
+
{
|
|
27
|
+
provider->_refcnt--;
|
|
28
|
+
if (provider->_refcnt == 0 && provider->destructor) {
|
|
29
|
+
provider->destructor(provider);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
void lcbcrypto_register(lcb_t instance, const char *name, lcbcrypto_PROVIDER *provider)
|
|
34
|
+
{
|
|
35
|
+
std::map< std::string, lcbcrypto_PROVIDER * >::iterator old = instance->crypto->find(name);
|
|
36
|
+
if (old != instance->crypto->end()) {
|
|
37
|
+
lcbcrypto_unref(old->second);
|
|
38
|
+
}
|
|
39
|
+
lcbcrypto_ref(provider);
|
|
40
|
+
(*instance->crypto)[name] = provider;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
void lcbcrypto_unregister(lcb_t instance, const char *name)
|
|
44
|
+
{
|
|
45
|
+
std::map< std::string, lcbcrypto_PROVIDER * >::iterator old = instance->crypto->find(name);
|
|
46
|
+
if (old != instance->crypto->end()) {
|
|
47
|
+
lcbcrypto_unref(old->second);
|
|
48
|
+
instance->crypto->erase(old);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
static bool lcbcrypto_is_valid(lcbcrypto_PROVIDER *provider)
|
|
53
|
+
{
|
|
54
|
+
if (!(provider && provider->_refcnt > 0)) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
if (provider->version != 0) {
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
if (provider->v.v0.sign && provider->v.v0.verify_signature == NULL) {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
return provider->v.v0.load_key && provider->v.v0.encrypt && provider->v.v0.decrypt;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
#define PROVIDER_LOAD_KEY(provider, type, keyid, key, nkey) \
|
|
67
|
+
(provider)->v.v0.load_key((provider), (type), (keyid), (key), (nkey))
|
|
68
|
+
|
|
69
|
+
#define PROVIDER_NEED_SIGN(provider) (provider)->v.v0.sign != NULL
|
|
70
|
+
#define PROVIDER_SIGN(provider, parts, nparts, sig, nsig) \
|
|
71
|
+
(provider)->v.v0.sign((provider), (parts), (nparts), (sig), (nsig));
|
|
72
|
+
#define PROVIDER_VERIFY_SIGNATURE(provider, parts, nparts, sig, nsig) \
|
|
73
|
+
(provider)->v.v0.verify_signature((provider), (parts), (nparts), (sig), (nsig));
|
|
74
|
+
|
|
75
|
+
#define PROVIDER_NEED_IV(provider) (provider)->v.v0.generate_iv != NULL
|
|
76
|
+
#define PROVIDER_GENERATE_IV(provider, iv, niv) (provider)->v.v0.generate_iv((provider), (iv), (niv))
|
|
77
|
+
|
|
78
|
+
#define PROVIDER_ENCRYPT(provider, ptext, nptext, key, nkey, iv, niv, ctext, nctext) \
|
|
79
|
+
(provider)->v.v0.encrypt((provider), (ptext), (nptext), (key), (nkey), (iv), (niv), (ctext), (nctext));
|
|
80
|
+
#define PROVIDER_DECRYPT(provider, ctext, nctext, key, nkey, iv, niv, ptext, nptext) \
|
|
81
|
+
(provider)->v.v0.decrypt((provider), (ctext), (nctext), (key), (nkey), (iv), (niv), (ptext), (nptext));
|
|
82
|
+
|
|
83
|
+
#define PROVIDER_RELEASE_BYTES(provider, bytes) \
|
|
84
|
+
if ((bytes) && (provider)->v.v0.release_bytes) { \
|
|
85
|
+
(provider)->v.v0.release_bytes((provider), (bytes)); \
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
static lcbcrypto_PROVIDER *lcb_get_provider(const lcb_st *instance, const std::string &alg)
|
|
90
|
+
{
|
|
91
|
+
const lcb_st::lcb_ProviderMap::iterator provider_iterator = (*instance->crypto).find(alg);
|
|
92
|
+
return provider_iterator != (*instance->crypto).end() ? provider_iterator->second : NULL;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
lcb_error_t lcbcrypto_encrypt_fields(lcb_t instance, lcbcrypto_CMDENCRYPT *cmd)
|
|
96
|
+
{
|
|
97
|
+
cmd->out = NULL;
|
|
98
|
+
cmd->nout = 0;
|
|
99
|
+
|
|
100
|
+
Json::Value jdoc;
|
|
101
|
+
if (!Json::Reader().parse(cmd->doc, cmd->doc + cmd->ndoc, jdoc)) {
|
|
102
|
+
return LCB_EINVAL;
|
|
103
|
+
}
|
|
104
|
+
bool changed = false;
|
|
105
|
+
std::string prefix = (cmd->prefix == NULL) ? "__crypt_" : cmd->prefix;
|
|
106
|
+
for (size_t ii = 0; ii < cmd->nfields; ii++) {
|
|
107
|
+
lcbcrypto_FIELDSPEC *field = cmd->fields + ii;
|
|
108
|
+
lcb_error_t rc;
|
|
109
|
+
uint8_t *key = NULL;
|
|
110
|
+
size_t nkey = 0;
|
|
111
|
+
|
|
112
|
+
lcbcrypto_PROVIDER *provider = lcb_get_provider(instance, field->alg);
|
|
113
|
+
if (!lcbcrypto_is_valid(provider)) {
|
|
114
|
+
continue;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
rc = PROVIDER_LOAD_KEY(provider, LCBCRYPTO_KEY_ENCRYPT, field->kid, &key, &nkey);
|
|
118
|
+
if (rc != LCB_SUCCESS) {
|
|
119
|
+
PROVIDER_RELEASE_BYTES(provider, key);
|
|
120
|
+
continue;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (jdoc.isMember(field->name)) {
|
|
124
|
+
std::string contents = Json::FastWriter().write(jdoc[field->name]);
|
|
125
|
+
Json::Value encrypted;
|
|
126
|
+
int ret;
|
|
127
|
+
|
|
128
|
+
uint8_t *iv = NULL;
|
|
129
|
+
char *biv = NULL;
|
|
130
|
+
size_t niv = 0;
|
|
131
|
+
lcb_SIZE nbiv = 0;
|
|
132
|
+
if (PROVIDER_NEED_IV(provider)) {
|
|
133
|
+
rc = PROVIDER_GENERATE_IV(provider, &iv, &niv);
|
|
134
|
+
if (rc != 0) {
|
|
135
|
+
PROVIDER_RELEASE_BYTES(provider, iv);
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
ret = lcb_base64_encode2(reinterpret_cast< char * >(iv), niv, &biv, &nbiv);
|
|
139
|
+
if (ret < 0) {
|
|
140
|
+
free(biv);
|
|
141
|
+
PROVIDER_RELEASE_BYTES(provider, iv);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
encrypted["iv"] = biv;
|
|
145
|
+
}
|
|
146
|
+
const uint8_t *ptext = reinterpret_cast< const uint8_t * >(contents.c_str());
|
|
147
|
+
uint8_t *ctext = NULL;
|
|
148
|
+
size_t nptext = contents.size(), nctext = 0;
|
|
149
|
+
rc = PROVIDER_ENCRYPT(provider, ptext, nptext, key, nkey, iv, niv, &ctext, &nctext);
|
|
150
|
+
PROVIDER_RELEASE_BYTES(provider, iv);
|
|
151
|
+
if (rc != LCB_SUCCESS) {
|
|
152
|
+
PROVIDER_RELEASE_BYTES(provider, ctext);
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
char *btext = NULL;
|
|
156
|
+
lcb_SIZE nbtext = 0;
|
|
157
|
+
ret = lcb_base64_encode2(reinterpret_cast< char * >(ctext), nctext, &btext, &nbtext);
|
|
158
|
+
PROVIDER_RELEASE_BYTES(provider, ctext);
|
|
159
|
+
if (ret < 0) {
|
|
160
|
+
free(btext);
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
encrypted["ciphertext"] = btext;
|
|
164
|
+
|
|
165
|
+
if (PROVIDER_NEED_SIGN(provider)) {
|
|
166
|
+
lcbcrypto_SIGV parts[4] = {};
|
|
167
|
+
size_t nparts = 0;
|
|
168
|
+
uint8_t *sig = NULL;
|
|
169
|
+
size_t nsig = 0;
|
|
170
|
+
|
|
171
|
+
parts[nparts].data = reinterpret_cast< const uint8_t * >(field->kid);
|
|
172
|
+
parts[nparts].len = strlen(field->kid);
|
|
173
|
+
nparts++;
|
|
174
|
+
parts[nparts].data = reinterpret_cast< const uint8_t * >(field->alg);
|
|
175
|
+
parts[nparts].len = strlen(field->alg);
|
|
176
|
+
nparts++;
|
|
177
|
+
if (biv) {
|
|
178
|
+
parts[nparts].data = reinterpret_cast< const uint8_t * >(biv);
|
|
179
|
+
parts[nparts].len = nbiv;
|
|
180
|
+
nparts++;
|
|
181
|
+
}
|
|
182
|
+
parts[nparts].data = reinterpret_cast< const uint8_t * >(btext);
|
|
183
|
+
parts[nparts].len = nbtext;
|
|
184
|
+
nparts++;
|
|
185
|
+
|
|
186
|
+
rc = PROVIDER_SIGN(provider, parts, nparts, &sig, &nsig);
|
|
187
|
+
if (rc != LCB_SUCCESS) {
|
|
188
|
+
PROVIDER_RELEASE_BYTES(provider, sig);
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
191
|
+
char *bsig = NULL;
|
|
192
|
+
lcb_SIZE nbsig = 0;
|
|
193
|
+
ret = lcb_base64_encode2(reinterpret_cast< char * >(sig), nsig, &bsig, &nbsig);
|
|
194
|
+
PROVIDER_RELEASE_BYTES(provider, sig);
|
|
195
|
+
if (ret < 0) {
|
|
196
|
+
free(bsig);
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
encrypted["sig"] = bsig;
|
|
200
|
+
free(bsig);
|
|
201
|
+
}
|
|
202
|
+
free(biv);
|
|
203
|
+
free(btext);
|
|
204
|
+
encrypted["kid"] = field->kid;
|
|
205
|
+
encrypted["alg"] = field->alg;
|
|
206
|
+
jdoc[prefix + field->name] = encrypted;
|
|
207
|
+
jdoc.removeMember(field->name);
|
|
208
|
+
changed = true;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
if (changed) {
|
|
212
|
+
std::string doc = Json::FastWriter().write(jdoc);
|
|
213
|
+
cmd->out = strdup(doc.c_str());
|
|
214
|
+
cmd->nout = strlen(cmd->out);
|
|
215
|
+
}
|
|
216
|
+
return LCB_SUCCESS;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
lcb_error_t lcbcrypto_decrypt_fields(lcb_t instance, lcbcrypto_CMDDECRYPT *cmd)
|
|
220
|
+
{
|
|
221
|
+
cmd->out = NULL;
|
|
222
|
+
cmd->nout = 0;
|
|
223
|
+
|
|
224
|
+
Json::Value jdoc;
|
|
225
|
+
if (!Json::Reader().parse(cmd->doc, cmd->doc + cmd->ndoc, jdoc)) {
|
|
226
|
+
return LCB_EINVAL;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
if (!jdoc.isObject()) {
|
|
230
|
+
return LCB_EINVAL;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
bool changed = false;
|
|
234
|
+
std::string prefix = (cmd->prefix == NULL) ? "__crypt_" : cmd->prefix;
|
|
235
|
+
|
|
236
|
+
const Json::Value::Members names = jdoc.getMemberNames();
|
|
237
|
+
for (Json::Value::Members::const_iterator ii = names.begin(); ii != names.end(); ii++) {
|
|
238
|
+
const std::string &name = *ii;
|
|
239
|
+
if (name.size() <= prefix.size()) {
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
242
|
+
if (prefix.compare(0, prefix.size(), name, 0, prefix.size()) != 0) {
|
|
243
|
+
continue;
|
|
244
|
+
}
|
|
245
|
+
Json::Value &encrypted = jdoc[name];
|
|
246
|
+
if (!encrypted.isObject()) {
|
|
247
|
+
continue;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
Json::Value &jalg = encrypted["alg"];
|
|
251
|
+
if (!jalg.isString()) {
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
const std::string &alg = jalg.asString();
|
|
255
|
+
|
|
256
|
+
Json::Value &jkid = encrypted["kid"];
|
|
257
|
+
if (!jkid.isString()) {
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
260
|
+
const std::string &kid = jkid.asString();
|
|
261
|
+
|
|
262
|
+
Json::Value &jiv = encrypted["iv"];
|
|
263
|
+
const char *biv = NULL;
|
|
264
|
+
size_t nbiv = 0;
|
|
265
|
+
if (jiv.isString()) {
|
|
266
|
+
biv = jiv.asCString();
|
|
267
|
+
nbiv = strlen(biv);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
int ret;
|
|
271
|
+
lcb_error_t rc;
|
|
272
|
+
|
|
273
|
+
lcbcrypto_PROVIDER *provider = lcb_get_provider(instance, alg);
|
|
274
|
+
if (!lcbcrypto_is_valid(provider)) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
Json::Value &jctext = encrypted["ciphertext"];
|
|
278
|
+
if (!jctext.isString()) {
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
281
|
+
const std::string &btext = jctext.asString();
|
|
282
|
+
|
|
283
|
+
if (PROVIDER_NEED_SIGN(provider)) {
|
|
284
|
+
Json::Value &jsig = encrypted["sig"];
|
|
285
|
+
if (!jsig.isString()) {
|
|
286
|
+
/* TODO: warn about missing signature? */
|
|
287
|
+
continue;
|
|
288
|
+
}
|
|
289
|
+
uint8_t *sig = NULL;
|
|
290
|
+
lcb_SIZE nsig = 0;
|
|
291
|
+
const std::string &bsig = jsig.asString();
|
|
292
|
+
ret = lcb_base64_decode2(bsig.c_str(), bsig.size(), reinterpret_cast< char ** >(&sig), &nsig);
|
|
293
|
+
if (ret < 0) {
|
|
294
|
+
PROVIDER_RELEASE_BYTES(provider, sig);
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
lcbcrypto_SIGV parts[4] = {};
|
|
299
|
+
size_t nparts = 0;
|
|
300
|
+
|
|
301
|
+
parts[nparts].data = reinterpret_cast< const uint8_t * >(kid.c_str());
|
|
302
|
+
parts[nparts].len = kid.size();
|
|
303
|
+
nparts++;
|
|
304
|
+
parts[nparts].data = reinterpret_cast< const uint8_t * >(alg.c_str());
|
|
305
|
+
parts[nparts].len = alg.size();
|
|
306
|
+
nparts++;
|
|
307
|
+
if (biv) {
|
|
308
|
+
parts[nparts].data = reinterpret_cast< const uint8_t * >(biv);
|
|
309
|
+
parts[nparts].len = nbiv;
|
|
310
|
+
nparts++;
|
|
311
|
+
}
|
|
312
|
+
parts[nparts].data = reinterpret_cast< const uint8_t * >(btext.c_str());
|
|
313
|
+
parts[nparts].len = btext.size();
|
|
314
|
+
nparts++;
|
|
315
|
+
|
|
316
|
+
rc = PROVIDER_VERIFY_SIGNATURE(provider, parts, nparts, sig, nsig);
|
|
317
|
+
free(sig);
|
|
318
|
+
if (rc != LCB_SUCCESS) {
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
uint8_t *ctext = NULL;
|
|
324
|
+
lcb_SIZE nctext = 0;
|
|
325
|
+
ret = lcb_base64_decode2(btext.c_str(), btext.size(), reinterpret_cast< char ** >(&ctext), &nctext);
|
|
326
|
+
if (ret < 0) {
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
uint8_t *key = NULL;
|
|
331
|
+
size_t nkey = 0;
|
|
332
|
+
rc = PROVIDER_LOAD_KEY(provider, LCBCRYPTO_KEY_DECRYPT, kid.c_str(), &key, &nkey);
|
|
333
|
+
if (rc != LCB_SUCCESS) {
|
|
334
|
+
free(ctext);
|
|
335
|
+
PROVIDER_RELEASE_BYTES(provider, key);
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
uint8_t *iv = NULL;
|
|
340
|
+
lcb_SIZE niv = 0;
|
|
341
|
+
if (biv) {
|
|
342
|
+
ret = lcb_base64_decode2(biv, nbiv, reinterpret_cast< char ** >(&iv), &niv);
|
|
343
|
+
if (ret < 0) {
|
|
344
|
+
free(ctext);
|
|
345
|
+
PROVIDER_RELEASE_BYTES(provider, key);
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
uint8_t *ptext = NULL;
|
|
351
|
+
size_t nptext = 0;
|
|
352
|
+
rc = PROVIDER_DECRYPT(provider, ctext, nctext, key, nkey, iv, niv, &ptext, &nptext);
|
|
353
|
+
PROVIDER_RELEASE_BYTES(provider, key);
|
|
354
|
+
free(ctext);
|
|
355
|
+
if (rc != LCB_SUCCESS) {
|
|
356
|
+
PROVIDER_RELEASE_BYTES(provider, ptext);
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
Json::Value frag;
|
|
360
|
+
char *json = reinterpret_cast< char * >(ptext);
|
|
361
|
+
bool valid_json = Json::Reader().parse(json, json + nptext, frag);
|
|
362
|
+
PROVIDER_RELEASE_BYTES(provider, ptext);
|
|
363
|
+
if (!valid_json) {
|
|
364
|
+
continue;
|
|
365
|
+
}
|
|
366
|
+
jdoc[name.substr(prefix.size())] = frag;
|
|
367
|
+
jdoc.removeMember(name);
|
|
368
|
+
changed = true;
|
|
369
|
+
}
|
|
370
|
+
if (changed) {
|
|
371
|
+
std::string doc = Json::FastWriter().write(jdoc);
|
|
372
|
+
cmd->out = strdup(doc.c_str());
|
|
373
|
+
cmd->nout = strlen(cmd->out);
|
|
374
|
+
}
|
|
375
|
+
return LCB_SUCCESS;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
lcb_error_t lcbcrypto_encrypt_document(lcb_t, lcbcrypto_CMDENCRYPT *)
|
|
379
|
+
{
|
|
380
|
+
return LCB_NOT_SUPPORTED;
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
lcb_error_t lcbcrypto_decrypt_document(lcb_t, lcbcrypto_CMDDECRYPT *)
|
|
384
|
+
{
|
|
385
|
+
return LCB_NOT_SUPPORTED;
|
|
386
|
+
}
|