aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/openssl.c382
1 files changed, 338 insertions, 44 deletions
diff --git a/src/openssl.c b/src/openssl.c
index 39612e0..a92df1a 100644
--- a/src/openssl.c
+++ b/src/openssl.c
@@ -77,12 +77,38 @@
#include "compat52.h"
#endif
+#define GNUC_2VER(M, m, p) (((M) * 10000) + ((m) * 100) + (p))
+#define GNUC_PREREQ(M, m, p) (__GNUC__ > 0 && GNUC_2VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) >= GNUC_2VER((M), (m), (p)))
+
+#define MSC_2VER(M, m, p) ((((M) + 6) * 10000000) + ((m) * 1000000) + (p))
+#define MSC_PREREQ(M, m, p) (_MSC_FULL_VER > 0 && _MSC_FULL_VER >= MSC_2VER((M), (m), (p)))
+
#define OPENSSL_PREREQ(M, m, p) \
(OPENSSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12)) && !defined LIBRESSL_VERSION_NUMBER)
#define LIBRESSL_PREREQ(M, m, p) \
(LIBRESSL_VERSION_NUMBER >= (((M) << 28) | ((m) << 20) | ((p) << 12)))
+#ifndef __has_builtin
+#define __has_builtin(x) 0
+#endif
+
+#ifndef __has_extension
+#define __has_extension(x) 0
+#endif
+
+#ifndef HAVE_C___ASSUME
+#define HAVE_C___ASSUME MSC_PREREQ(8,0,0)
+#endif
+
+#ifndef HAVE_C___BUILTIN_UNREACHABLE
+#define HAVE_C___BUILTIN_UNREACHABLE (GNUC_PREREQ(4,5,0) || __has_builtin(__builtin_unreachable))
+#endif
+
+#ifndef HAVE_C___DECLSPEC_NORETURN
+#define HAVE_C___DECLSPEC_NORETURN MSC_PREREQ(8,0,0)
+#endif
+
#ifndef HAVE_ASN1_STRING_GET0_DATA
#define HAVE_ASN1_STRING_GET0_DATA OPENSSL_PREREQ(1,1,0)
#endif
@@ -167,6 +193,10 @@
#define HAVE_EVP_PKEY_BASE_ID OPENSSL_PREREQ(1,1,0)
#endif
+#ifndef HAVE_EVP_PKEY_CTX_NEW
+#define HAVE_EVP_PKEY_CTX_NEW (OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0))
+#endif
+
#ifndef HAVE_EVP_PKEY_GET0
#define HAVE_EVP_PKEY_GET0 OPENSSL_PREREQ(1,1,0)
#endif
@@ -199,6 +229,10 @@
#define HAVE_RSA_GET0_KEY OPENSSL_PREREQ(1,1,0)
#endif
+#ifndef HAVE_RSA_PKCS1_PSS_PADDING
+#define HAVE_RSA_PKCS1_PSS_PADDING (defined RSA_PKCS1_PSS_PADDING || OPENSSL_PREREQ(1,0,0) || LIBRESSL_PREREQ(2,0,0))
+#endif
+
#ifndef HAVE_RSA_SET0_CRT_PARAMS
#define HAVE_RSA_SET0_CRT_PARAMS OPENSSL_PREREQ(1,1,0)
#endif
@@ -255,6 +289,10 @@
#define HAVE_X509_STORE_REFERENCES (!OPENSSL_PREREQ(1,1,0))
#endif
+#ifndef HAVE_X509_STORE_UP_REF
+#define HAVE_X509_STORE_UP_REF OPENSSL_PREREQ(1,1,0)
+#endif
+
#ifndef HAVE_X509_UP_REF
#define HAVE_X509_UP_REF OPENSSL_PREREQ(1,1,0)
#endif
@@ -312,6 +350,13 @@
#define NOTUSED
#endif
+#if HAVE_C___BUILTIN_UNREACHABLE
+#define NOTREACHED __builtin_unreachable()
+#elif HAVE_C___ASSUME
+#define NOTREACHED __assume(0)
+#else
+#define NOTREACHED (void)0
+#endif
#define countof(a) (sizeof (a) / sizeof *(a))
#define endof(a) (&(a)[countof(a)])
@@ -706,6 +751,8 @@ static size_t auxS_obj2txt(void *dst, size_t lim, const ASN1_OBJECT *obj) {
return auxS_obj2id(dst, lim, obj);
} /* auxS_obj2txt() */
+static const EVP_MD *auxS_todigest(const char *name, EVP_PKEY *key, const EVP_MD *def);
+
static _Bool auxS_isoid(const char *txt) {
return (*txt >= '0' && *txt <= '9');
} /* auxS_isoid() */
@@ -1092,8 +1139,9 @@ static const char *auxL_pusherror(lua_State *L, int error, const char *fun) {
static int auxL_error(lua_State *L, int error, const char *fun) {
auxL_pusherror(L, error, fun);
-
- return lua_error(L);
+ lua_error(L);
+ NOTREACHED;
+ return 0;
} /* auxL_error() */
static const char *auxL_pushnid(lua_State *L, int nid) {
@@ -1108,6 +1156,8 @@ static const char *auxL_pushnid(lua_State *L, int nid) {
return lua_tostring(L, -1);
} /* auxL_pushnid() */
+static const EVP_MD *auxL_optdigest(lua_State *L, int index, EVP_PKEY *key, const EVP_MD *def);
+
/*
* dl - dynamically loaded module management
@@ -1587,6 +1637,18 @@ static void compat_init_X509_STORE_onfree(void *store, void *data NOTUSED, CRYPT
compat.tmp.store = NULL;
} /* compat_init_X509_STORE_onfree() */
+#if !HAVE_X509_STORE_UP_REF
+#define X509_STORE_up_ref(...) compat_X509_STORE_up_ref(__VA_ARGS__)
+
+static int compat_X509_STORE_up_ref(X509_STORE *crt) {
+ /* our caller should already have had a proper reference */
+ if (CRYPTO_add(&crt->references, 1, CRYPTO_LOCK_X509_STORE) < 2)
+ return 0; /* fail */
+
+ return 1;
+} /* compat_X509_STORE_up_ref() */
+#endif
+
#if !HAVE_X509_UP_REF
#define X509_up_ref(...) compat_X509_up_ref(__VA_ARGS__)
@@ -1688,6 +1750,53 @@ sslerr:
/*
+ * Auxiliary OpenSSL API routines (with dependencies on OpenSSL compat)
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static const EVP_MD *auxS_todigest(const char *name, EVP_PKEY *key, const EVP_MD *def) {
+ const EVP_MD *md;
+ int nid;
+
+ if (name) {
+ if ((md = EVP_get_digestbyname(name)))
+ return md;
+ } else if (key) {
+ if ((EVP_PKEY_get_default_digest_nid(key, &nid) > 0)) {
+ if ((md = EVP_get_digestbynid(nid)))
+ return md;
+ }
+ }
+
+ return def;
+} /* auxS_todigest() */
+
+
+/*
+ * Auxiliary Lua API routines (with dependencies on OpenSSL compat)
+ *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+static const EVP_MD *auxL_optdigest(lua_State *L, int index, EVP_PKEY *key, const EVP_MD *def) {
+ const char *name = luaL_optstring(L, index, NULL);
+ const EVP_MD *md;
+
+ if ((md = auxS_todigest(name, key, NULL)))
+ return md;
+
+ if (name) {
+ luaL_argerror(L, index, lua_pushfstring(L, "invalid digest type (%s)", name));
+ NOTREACHED;
+ } else if (key) {
+ luaL_argerror(L, index, lua_pushfstring(L, "no digest type for key type (%d)", EVP_PKEY_base_id(key)));
+ NOTREACHED;
+ }
+
+ return def;
+} /* auxL_optdigest() */
+
+
+/*
* External Application Data Hooks
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
@@ -3180,6 +3289,123 @@ static int pk_setPrivateKey(lua_State *L) {
return 1;
} /* pk_setPrivateKey() */
+#if HAVE_EVP_PKEY_CTX_NEW
+static int pk_decrypt(lua_State *L) {
+ size_t outlen, inlen;
+ EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS);
+ EVP_PKEY_CTX *ctx;
+ const char *str = luaL_checklstring(L, 2, &inlen);
+ BIO *bio;
+ BUF_MEM *buf;
+ int rsaPadding = RSA_PKCS1_PADDING; /* default for `openssl rsautl` */
+ int base_type = EVP_PKEY_base_id(key);
+
+ if (lua_istable(L, 3)) {
+ if (base_type == EVP_PKEY_RSA) {
+ lua_getfield(L, 3, "rsaPadding");
+ rsaPadding = luaL_optint(L, -1, rsaPadding);
+ lua_pop(L, 1);
+ }
+ }
+
+ bio = getbio(L);
+ BIO_get_mem_ptr(bio, &buf);
+
+ if (!(ctx = EVP_PKEY_CTX_new(key, NULL)))
+ goto sslerr;
+
+ if (EVP_PKEY_decrypt_init(ctx) <= 0)
+ goto sslerr;
+
+ if (base_type == EVP_PKEY_RSA && !EVP_PKEY_CTX_set_rsa_padding(ctx, rsaPadding))
+ goto sslerr;
+
+ if (EVP_PKEY_decrypt(ctx, NULL, &outlen, (const unsigned char *)str, inlen) <= 0)
+ goto sslerr;
+
+ if (!BUF_MEM_grow_clean(buf, outlen))
+ goto sslerr;
+
+ if (EVP_PKEY_decrypt(ctx, (unsigned char *)buf->data, &outlen, (const unsigned char *)str, inlen) <= 0)
+ goto sslerr;
+
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+
+ lua_pushlstring(L, buf->data, outlen);
+
+ BIO_reset(bio);
+
+ return 1;
+sslerr:
+ if (ctx) {
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+ }
+ BIO_reset(bio);
+
+ return auxL_error(L, auxL_EOPENSSL, "pkey:decrypt");
+} /* pk_decrypt() */
+#endif
+
+#if HAVE_EVP_PKEY_CTX_NEW
+static int pk_encrypt(lua_State *L) {
+ size_t outlen, inlen;
+ EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS);
+ EVP_PKEY_CTX *ctx;
+ const char *str = luaL_checklstring(L, 2, &inlen);
+ BIO *bio;
+ BUF_MEM *buf;
+ int rsaPadding = RSA_PKCS1_PADDING; /* default for `openssl rsautl` */
+ int base_type = EVP_PKEY_base_id(key);
+
+ if (lua_istable(L, 3)) {
+ if (base_type == EVP_PKEY_RSA) {
+ lua_getfield(L, 3, "rsaPadding");
+ rsaPadding = luaL_optint(L, -1, rsaPadding);
+ lua_pop(L, 1);
+ }
+ }
+
+ bio = getbio(L);
+ BIO_get_mem_ptr(bio, &buf);
+
+ if (!(ctx = EVP_PKEY_CTX_new(key, NULL)))
+ goto sslerr;
+
+ if (EVP_PKEY_encrypt_init(ctx) <= 0)
+ goto sslerr;
+
+ if (base_type == EVP_PKEY_RSA && !EVP_PKEY_CTX_set_rsa_padding(ctx, rsaPadding))
+ goto sslerr;
+
+ if (EVP_PKEY_encrypt(ctx, NULL, &outlen, (const unsigned char *)str, inlen) <= 0)
+ goto sslerr;
+
+ if (!BUF_MEM_grow_clean(buf, outlen))
+ goto sslerr;
+
+ if (EVP_PKEY_encrypt(ctx, (unsigned char *)buf->data, &outlen, (const unsigned char *)str, inlen) <= 0)
+ goto sslerr;
+
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+
+ lua_pushlstring(L, buf->data, outlen);
+
+ BIO_reset(bio);
+
+ return 1;
+sslerr:
+ if (ctx) {
+ EVP_PKEY_CTX_free(ctx);
+ ctx = NULL;
+ }
+ BIO_reset(bio);
+
+ return auxL_error(L, auxL_EOPENSSL, "pkey:encrypt");
+} /* pk_encrypt() */
+#endif
static int pk_sign(lua_State *L) {
EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS);
@@ -3337,18 +3563,11 @@ static int pk_toPEM(lua_State *L) {
static int pk_getDefaultDigestName(lua_State *L) {
EVP_PKEY *key = checksimple(L, 1, PKEY_CLASS);
int nid;
- char txt[256];
- size_t len;
if (!(EVP_PKEY_get_default_digest_nid(key, &nid) > 0))
return auxL_error(L, auxL_EOPENSSL, "pkey:getDefaultDigestName");
- if (!(len = auxS_nid2txt(txt, sizeof txt, nid)))
- return auxL_error(L, auxL_EOPENSSL, "pkey:getDefaultDigestName");
- if (len > sizeof txt)
- return auxL_error(L, EOVERFLOW, "pkey:getDefaultDigestName");
-
- lua_pushlstring(L, txt, len);
+ auxL_pushnid(L, nid);
return 1;
} /* pk_getDefaultDigestName() */
@@ -3907,6 +4126,10 @@ static const auxL_Reg pk_methods[] = {
{ "type", &pk_type },
{ "setPublicKey", &pk_setPublicKey },
{ "setPrivateKey", &pk_setPrivateKey },
+#if HAVE_EVP_PKEY_CTX_NEW
+ { "decrypt", &pk_decrypt },
+ { "encrypt", &pk_encrypt },
+#endif
{ "sign", &pk_sign },
{ "verify", &pk_verify },
{ "getDefaultDigestName", &pk_getDefaultDigestName },
@@ -3945,10 +4168,23 @@ static void pk_luainit(lua_State *L, _Bool reset) {
lua_pop(L, 2);
} /* pk_luainit() */
+static const auxL_IntegerReg pk_rsa_pad_opts[] = {
+ { "RSA_PKCS1_PADDING", RSA_PKCS1_PADDING }, // PKCS#1 padding
+ { "RSA_SSLV23_PADDING", RSA_SSLV23_PADDING }, // SSLv23 padding
+ { "RSA_NO_PADDING", RSA_NO_PADDING }, // no padding
+ { "RSA_PKCS1_OAEP_PADDING", RSA_PKCS1_OAEP_PADDING }, // OAEP padding (encrypt and decrypt only)
+ { "RSA_X931_PADDING", RSA_X931_PADDING }, // (signature operations only)
+#if HAVE_RSA_PKCS1_PSS_PADDING
+ { "RSA_PKCS1_PSS_PADDING", RSA_PKCS1_PSS_PADDING }, // (sign and verify only)
+#endif
+ { NULL, 0 },
+};
+
int luaopen__openssl_pkey(lua_State *L) {
initall(L);
auxL_newlib(L, pk_globals, 0);
+ auxL_setintegers(L, pk_rsa_pad_opts);
return 1;
} /* luaopen__openssl_pkey() */
@@ -5656,49 +5892,50 @@ static int xc_setPublicKey(lua_State *L) {
static int xc_getPublicKeyDigest(lua_State *L) {
- ASN1_BIT_STRING *pk = X509_get0_pubkey_bitstr(checksimple(L, 1, X509_CERT_CLASS));
- const char *id = luaL_optstring(L, 2, "sha1");
+ X509 *crt = checksimple(L, 1, X509_CERT_CLASS);
+ EVP_PKEY *key;
const EVP_MD *md;
+ ASN1_BIT_STRING *bitstr;
unsigned char digest[EVP_MAX_MD_SIZE];
unsigned int len;
- if (!(md = EVP_get_digestbyname(id)))
- return luaL_error(L, "x509.cert:getPublicKeyDigest: %s: invalid digest type", id);
+ if (!(key = X509_get_pubkey(crt)))
+ return luaL_argerror(L, 1, "no public key");
+ md = auxL_optdigest(L, 2, key, NULL);
+ bitstr = X509_get0_pubkey_bitstr(crt);
- if (!EVP_Digest(pk->data, pk->length, digest, &len, md, NULL))
+ if (!EVP_Digest(bitstr->data, bitstr->length, digest, &len, md, NULL))
return auxL_error(L, auxL_EOPENSSL, "x509.cert:getPublicKeyDigest");
-
lua_pushlstring(L, (char *)digest, len);
return 1;
} /* xc_getPublicKeyDigest() */
-static const EVP_MD *xc_signature(lua_State *L, int index, EVP_PKEY *key) {
- const char *id;
- const EVP_MD *md;
+#if 0
+/*
+ * TODO: X509_get_signature_type always seems to return NID_undef. Are we
+ * using it wrong or is it broken?
+ */
+static int xc_getSignatureName(lua_State *L) {
+ X509 *crt = checksimple(L, 1, X509_CERT_CLASS);
int nid;
- if ((id = luaL_optstring(L, index, NULL))) {
- if (!(md = EVP_get_digestbyname(id)))
- goto unknown;
- } else {
- if (!(EVP_PKEY_get_default_digest_nid(key, &nid) > 0))
- goto unknown;
- if (!(md = EVP_get_digestbynid(nid)))
- goto unknown;
- }
+ if (NID_undef == (nid = X509_get_signature_type(crt)))
+ return 0;
+
+ auxL_pushnid(L, nid);
+
+ return 1;
+} /* xc_getSignatureName() */
+#endif
- return md;
-unknown:
- return EVP_sha1();
-} /* xc_signature() */
static int xc_sign(lua_State *L) {
X509 *crt = checksimple(L, 1, X509_CERT_CLASS);
EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS);
- if (!X509_sign(crt, key, xc_signature(L, 3, key)))
+ if (!X509_sign(crt, key, auxL_optdigest(L, 3, key, NULL)))
return auxL_error(L, auxL_EOPENSSL, "x509.cert:sign");
lua_pushboolean(L, 1);
@@ -5838,6 +6075,9 @@ static const auxL_Reg xc_methods[] = {
{ "getPublicKey", &xc_getPublicKey },
{ "setPublicKey", &xc_setPublicKey },
{ "getPublicKeyDigest", &xc_getPublicKeyDigest },
+#if 0
+ { "getSignatureName", &xc_getSignatureName },
+#endif
{ "sign", &xc_sign },
{ "text", &xc_text },
{ "tostring", &xc__tostring },
@@ -6091,7 +6331,7 @@ static int xr_sign(lua_State *L) {
X509_REQ *csr = checksimple(L, 1, X509_CSR_CLASS);
EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS);
- if (!X509_REQ_sign(csr, key, xc_signature(L, 3, key)))
+ if (!X509_REQ_sign(csr, key, auxL_optdigest(L, 3, key, NULL)))
return auxL_error(L, auxL_EOPENSSL, "x509.csr:sign");
lua_pushboolean(L, 1);
@@ -6466,7 +6706,7 @@ static int xx_sign(lua_State *L) {
X509_CRL *crl = checksimple(L, 1, X509_CRL_CLASS);
EVP_PKEY *key = checksimple(L, 2, PKEY_CLASS);
- if (!X509_CRL_sign(crl, key, xc_signature(L, 3, key)))
+ if (!X509_CRL_sign(crl, key, auxL_optdigest(L, 3, key, NULL)))
return auxL_error(L, auxL_EOPENSSL, "x509.crl:sign");
lua_pushboolean(L, 1);
@@ -6744,6 +6984,16 @@ static int xs_new(lua_State *L) {
} /* xs_new() */
+static X509_STORE *xs_push(lua_State *L, X509_STORE *store) {
+ X509_STORE **ud = prepsimple(L, X509_STORE_CLASS);
+
+ X509_STORE_up_ref(store);
+ *ud = store;
+
+ return *ud;
+} /* xs_push() */
+
+
static int xs_interpose(lua_State *L) {
return interpose(L, X509_STORE_CLASS);
} /* xs_interpose() */
@@ -6752,17 +7002,24 @@ static int xs_interpose(lua_State *L) {
static int xs_add(lua_State *L) {
X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS);
int i, top = lua_gettop(L);
+ X509 *crt, *crt_dup;
+ X509_CRL *crl, *crl_dup;
for (i = 2; i <= top; i++) {
- if (lua_isuserdata(L, i)) {
- X509 *crt = checksimple(L, i, X509_CERT_CLASS);
- X509 *dup;
+ if ((crt = testsimple(L, i, X509_CERT_CLASS))) {
+ if (!(crt_dup = X509_dup(crt)))
+ return auxL_error(L, auxL_EOPENSSL, "x509.store:add");
- if (!(dup = X509_dup(crt)))
+ if (!X509_STORE_add_cert(store, crt_dup)) {
+ X509_free(crt_dup);
+ return auxL_error(L, auxL_EOPENSSL, "x509.store:add");
+ }
+ } else if ((crl = testsimple(L, i, X509_CRL_CLASS))) {
+ if (!(crl_dup = X509_CRL_dup(crl)))
return auxL_error(L, auxL_EOPENSSL, "x509.store:add");
- if (!X509_STORE_add_cert(store, dup)) {
- X509_free(dup);
+ if (!X509_STORE_add_crl(store, crl_dup)) {
+ X509_CRL_free(crl_dup);
return auxL_error(L, auxL_EOPENSSL, "x509.store:add");
}
} else {
@@ -6789,6 +7046,18 @@ static int xs_add(lua_State *L) {
} /* xs_add() */
+static int xs_addDefaults(lua_State *L) {
+ X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS);
+
+ if (!X509_STORE_set_default_paths(store))
+ return auxL_error(L, auxL_EOPENSSL, "x509.store:addDefaults");
+
+ lua_pushvalue(L, 1);
+
+ return 1;
+} /* xs_addDefaults() */
+
+
static int xs_verify(lua_State *L) {
X509_STORE *store = checksimple(L, 1, X509_STORE_CLASS);
X509 *crt = checksimple(L, 2, X509_CERT_CLASS);
@@ -6871,9 +7140,10 @@ static int xs__gc(lua_State *L) {
static const auxL_Reg xs_methods[] = {
- { "add", &xs_add },
- { "verify", &xs_verify },
- { NULL, NULL },
+ { "add", &xs_add },
+ { "addDefaults", &xs_addDefaults },
+ { "verify", &xs_verify },
+ { NULL, NULL },
};
static const auxL_Reg xs_metatable[] = {
@@ -6892,6 +7162,15 @@ int luaopen__openssl_x509_store(lua_State *L) {
auxL_newlib(L, xs_globals, 0);
+ lua_pushstring(L, X509_get_default_cert_dir());
+ lua_setfield(L, -2, "CERT_DIR");
+ lua_pushstring(L, X509_get_default_cert_file());
+ lua_setfield(L, -2, "CERT_FILE");
+ lua_pushstring(L, X509_get_default_cert_dir_env());
+ lua_setfield(L, -2, "CERT_DIR_EVP");
+ lua_pushstring(L, X509_get_default_cert_file_env());
+ lua_setfield(L, -2, "CERT_FILE_EVP");
+
return 1;
} /* luaopen__openssl_x509_store() */
@@ -7237,6 +7516,20 @@ static int sx_setStore(lua_State *L) {
} /* sx_setStore() */
+static int sx_getStore(lua_State *L) {
+ SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS);
+ X509_STORE *store;
+
+ if((store = SSL_CTX_get_cert_store(ctx))) {
+ xs_push(L, store);
+ } else {
+ lua_pushnil(L);
+ }
+
+ return 1;
+} /* sx_getStore() */
+
+
static int sx_setVerify(lua_State *L) {
SSL_CTX *ctx = checksimple(L, 1, SSL_CTX_CLASS);
int mode = luaL_optint(L, 2, -1);
@@ -7503,6 +7796,7 @@ static const auxL_Reg sx_methods[] = {
{ "getOptions", &sx_getOptions },
{ "clearOptions", &sx_clearOptions },
{ "setStore", &sx_setStore },
+ { "getStore", &sx_getStore },
{ "setVerify", &sx_setVerify },
{ "getVerify", &sx_getVerify },
{ "setCertificate", &sx_setCertificate },