aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2024-02-01 23:19:49 +0100
committerChristian Grothoff <christian@grothoff.org>2024-02-01 23:19:49 +0100
commitf0a05b8694fc6c65a6643e62ae309e48399d7066 (patch)
tree6f287c5b34fcc42ae845ca5ca0649642b701af93
parent37bfb3da42186329f9cf4fa35dabc3fa5b5a2258 (diff)
add new TOTP-specfic JSON parsers
-rw-r--r--src/include/taler_crypto_lib.h16
-rw-r--r--src/include/taler_json_lib.h31
-rw-r--r--src/json/Makefile.am2
-rw-r--r--src/json/json_helper.c150
-rw-r--r--src/util/Makefile.am2
-rw-r--r--src/util/crypto_confirmation.c41
6 files changed, 217 insertions, 25 deletions
diff --git a/src/include/taler_crypto_lib.h b/src/include/taler_crypto_lib.h
index b872af08d..e3ae829fd 100644
--- a/src/include/taler_crypto_lib.h
+++ b/src/include/taler_crypto_lib.h
@@ -938,6 +938,22 @@ GNUNET_NETWORK_STRUCT_END
/**
+ * Compute RFC 3548 base32 decoding of @a val and write
+ * result to @a udata.
+ *
+ * @param val value to decode
+ * @param val_size number of bytes in @a val
+ * @param key is the val in bits
+ * @param key_len is the size of @a key
+ */
+int
+TALER_rfc3548_base32decode (const char *val,
+ size_t val_size,
+ void *key,
+ size_t key_len);
+
+
+/**
* @brief Builds POS confirmation token to verify payment.
*
* @param pos_key encoded key for verification payment
diff --git a/src/include/taler_json_lib.h b/src/include/taler_json_lib.h
index 859ec8879..98e565f0c 100644
--- a/src/include/taler_json_lib.h
+++ b/src/include/taler_json_lib.h
@@ -1,6 +1,6 @@
/*
This file is part of TALER
- Copyright (C) 2014, 2015, 2016, 2021, 2022 Taler Systems SA
+ Copyright (C) 2014-2024 Taler Systems SA
TALER is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
@@ -59,7 +59,6 @@ struct TALER_EncryptedContract
*/
size_t econtract_size;
-
};
@@ -287,6 +286,34 @@ TALER_JSON_spec_age_commitment (const char *name,
/**
+ * Provide specification to parse an OTP key.
+ * An OTP key must be an RFC 3548 base32-encoded
+ * value (so NOT our usual Crockford-base32 encoding!).
+ *
+ * @param name name of the OTP key field in the JSON
+ * @param[out] otp_key where to store the OTP key
+ * @return spec for parsing an age commitment
+ */
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_otp_key (const char *name,
+ const char **otp_key);
+
+
+/**
+ * Provide specification to parse an OTP method type.
+ * The value could be provided as an integer or
+ * as a descriptive string.
+ *
+ * @param name name of the OTP method type in the JSON
+ * @param[out] mca where to store the method type
+ * @return spec for parsing an age commitment
+ */
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_otp_type (const char *name,
+ enum TALER_MerchantConfirmationAlgorithm *mca);
+
+
+/**
* Generate specification to parse all fees for
* a denomination under a prefix @a pfx.
*
diff --git a/src/json/Makefile.am b/src/json/Makefile.am
index 6886b285a..ce863cb7e 100644
--- a/src/json/Makefile.am
+++ b/src/json/Makefile.am
@@ -16,7 +16,7 @@ libtalerjson_la_SOURCES = \
json_pack.c \
json_wire.c
libtalerjson_la_LDFLAGS = \
- -version-info 2:0:0 \
+ -version-info 3:0:1 \
-no-undefined
libtalerjson_la_LIBADD = \
$(top_builddir)/src/util/libtalerutil.la \
diff --git a/src/json/json_helper.c b/src/json/json_helper.c
index 01ca45f2b..0a533610b 100644
--- a/src/json/json_helper.c
+++ b/src/json/json_helper.c
@@ -1666,4 +1666,154 @@ TALER_JSON_spec_version (const char *field,
}
+/**
+ * Parse given JSON object to an OTP key.
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_otp_key (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ const char *pos_key;
+
+ (void) cls;
+ pos_key = json_string_value (root);
+ if (NULL == pos_key)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ {
+ size_t pos_key_length = strlen (pos_key);
+ void *key; /* pos_key in binary */
+ size_t key_len; /* length of the key */
+ int dret;
+
+ key_len = pos_key_length * 5 / 8;
+ key = GNUNET_malloc (key_len);
+ dret = TALER_rfc3548_base32decode (pos_key,
+ pos_key_length,
+ key,
+ key_len);
+ if (-1 == dret)
+ {
+ GNUNET_free (key);
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (key);
+ }
+ *(const char **) spec->ptr = pos_key;
+ return GNUNET_OK;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_otp_key (const char *name,
+ const char **otp_key)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_otp_key,
+ .field = name,
+ .ptr = otp_key
+ };
+
+ *otp_key = NULL;
+ return ret;
+}
+
+
+/**
+ * Parse given JSON object to `enum TALER_MerchantConfirmationAlgorithm`
+ *
+ * @param cls closure, NULL
+ * @param root the json object representing data
+ * @param[out] spec where to write the data
+ * @return #GNUNET_OK upon successful parsing; #GNUNET_SYSERR upon error
+ */
+static enum GNUNET_GenericReturnValue
+parse_otp_type (void *cls,
+ json_t *root,
+ struct GNUNET_JSON_Specification *spec)
+{
+ static const struct Entry
+ {
+ const char *name;
+ enum TALER_MerchantConfirmationAlgorithm val;
+ } lt [] = {
+ { .name = "NONE",
+ .val = TALER_MCA_NONE },
+ { .name = "TOTP_WITHOUT_PRICE",
+ .val = TALER_MCA_WITHOUT_PRICE },
+ { .name = "TOTP_WITH_PRICE",
+ .val = TALER_MCA_WITH_PRICE },
+ { .name = NULL,
+ .val = TALER_MCA_NONE },
+ };
+ enum TALER_MerchantConfirmationAlgorithm *res
+ = (enum TALER_MerchantConfirmationAlgorithm *) spec->ptr;
+
+ (void) cls;
+ if (json_is_string (root))
+ {
+ const char *str;
+
+ str = json_string_value (root);
+ if (NULL == str)
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ for (unsigned int i = 0; NULL != lt[i].name; i++)
+ {
+ if (0 == strcasecmp (str,
+ lt[i].name))
+ {
+ *res = lt[i].val;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ }
+ if (json_is_integer (root))
+ {
+ json_int_t val;
+
+ val = json_integer_value (root);
+ for (unsigned int i = 0; NULL != lt[i].name; i++)
+ {
+ if (val == lt[i].val)
+ {
+ *res = lt[i].val;
+ return GNUNET_OK;
+ }
+ }
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+}
+
+
+struct GNUNET_JSON_Specification
+TALER_JSON_spec_otp_type (const char *name,
+ enum TALER_MerchantConfirmationAlgorithm *mca)
+{
+ struct GNUNET_JSON_Specification ret = {
+ .parser = &parse_otp_type,
+ .field = name,
+ .ptr = mca
+ };
+
+ *mca = TALER_MCA_NONE;
+ return ret;
+}
+
+
/* end of json/json_helper.c */
diff --git a/src/util/Makefile.am b/src/util/Makefile.am
index 478f75cfe..914ddfdf1 100644
--- a/src/util/Makefile.am
+++ b/src/util/Makefile.am
@@ -120,7 +120,7 @@ libtalerutil_la_LIBADD = \
-lm
libtalerutil_la_LDFLAGS = \
- -version-info 1:0:0 \
+ -version-info 2:0:1 \
-no-undefined
diff --git a/src/util/crypto_confirmation.c b/src/util/crypto_confirmation.c
index f19fc4a3c..204c373da 100644
--- a/src/util/crypto_confirmation.c
+++ b/src/util/crypto_confirmation.c
@@ -112,20 +112,11 @@ compute_totp (struct GNUNET_TIME_Timestamp ts,
}
-/**
- * Compute RFC 3548 base32 decoding of @a val and write
- * result to @a udata.
- *
- * @param val value to decode
- * @param val_size number of bytes in @a val
- * @param key is the val in bits
- * @param key_len is the size of @a key
- */
-static int
-base32decode (const char *val,
- size_t val_size,
- void *key,
- size_t key_len)
+int
+TALER_rfc3548_base32decode (const char *val,
+ size_t val_size,
+ void *key,
+ size_t key_len)
{
/**
* 32 characters for decoding, using RFC 3548.
@@ -142,13 +133,21 @@ base32decode (const char *val,
if ((rpos < val_size) && (vbit < 8))
{
char c = val[rpos++];
- if (c == '=') // padding character
+
+ if (c == '=')
{
- break;
+ /* padding character */
+ if (rpos == val_size)
+ break; /* Ok, 1x '=' padding is allowed */
+ if ( ('=' == val[rpos]) &&
+ (rpos + 1 == val_size) )
+ break; /* Ok, 2x '=' padding is allowed */
+ return -1; /* invalid padding */
}
const char *p = strchr (decTable__, toupper (c));
if (! p)
- { // invalid character
+ {
+ /* invalid character */
return -1;
}
bits = (bits << 5) | (p - decTable__);
@@ -226,10 +225,10 @@ TALER_build_pos_confirmation (const char *pos_key,
return NULL;
key_len = pos_key_length * 5 / 8;
key = GNUNET_malloc (key_len);
- dret = base32decode (pos_key,
- pos_key_length,
- key,
- key_len);
+ dret = TALER_rfc3548_base32decode (pos_key,
+ pos_key_length,
+ key,
+ key_len);
if (-1 == dret)
{
GNUNET_free (key);