aboutsummaryrefslogtreecommitdiff
path: root/doc/cs/content/4_3_implementation.tex
blob: 879e69e8f2d8db5be84db9e447d889978acb737a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
\chapter{Implementation}
\label{chap:implement}
This chapter gives an overview on the implementation challenges and discusses special parts in the implementation.


\section{Signature Scheme Operations}
The signature scheme operations are implemented in the GNUnet core repository \cite{gnunet-git} (and have been merged into the master branch).
This would allow other GNUnet projects to use our implementation of the Clause Blind Schnorr Signature Scheme.

The implementation is done in multiple locations:
\begin{itemize}
  \item \texttt{src/include/gnunet\_crypto\_lib.h}:
        This header file is included when using GNUnet's cryptography implementation.
  \item \texttt{src/util/crypto\_cs.c}:
        The functions specified in \texttt{gnunet\_crypto\_lib.h} will be implemented here.
  \item \texttt{src/util/test\_crypto\_cs.c}:
        The test cases for the signature scheme will be implemented here.
  \item \texttt{src/util/perf\_crypto\_cs.c}:
        This file houses the implementation of a small program that will be used to compare the performance against the blind RSA Signature Scheme.
\end{itemize}

The specification explaining the \ac{API} can be found in section \ref{sec:specification-signature-scheme}. There are two internal functions that have to be explained further in this section.

The \texttt{map\_to\_scalar\_subgroup} function clamps scalars, which is necessary for values that are derived using a \gls{hkdf}.
It sets the three least significant bits to zero (making the scalar a multiple of 8), sets the most significant bit to zero and the second-most significant bit to one.
This process is further described in \cite{rfc7748} and \cite{madden:curve25519-clamping}.

\begin{lstlisting}[style=bfh-c, language=C, caption={Function map\_to\_scalar\_subgroup - Crypto API}, label={lst:map-to-scalar}]
static void
map_to_scalar_subgroup (struct GNUNET_CRYPTO_Cs25519Scalar *scalar)
{
    scalar->d[0] &= 248;
    scalar->d[31] &= 127;
    scalar->d[31] |= 64;
}
\end{lstlisting}

Another important function is the \gls{fdh} (see \ref{sec:schnorr-sig}) used to map the message to a scalar.
GNUnet provides a \gls{fdh} function, which expects libgcrypt's multi precision format.
A conversion function is provided by GNUnet, which requires the data to be in big endian format.
Since libsodium uses a little endian representation, the conversion process must include endianness conversion.
The complete \gls{fdh} including the required conversions is implemented in the function described in listing \ref{lst:cs-fdh}.
\begin{lstlisting}[style=bfh-c, language=C, caption={Function cs\_full\_domain\_hash - Crypto API}, label={lst:cs-fdh}]
static void
cs_full_domain_hash (const struct GNUNET_CRYPTO_CsRPublic *r_dash,
                     const void *msg,
                     size_t msg_len,
                     const struct GNUNET_CRYPTO_CsPublicKey *pub,
                     struct GNUNET_CRYPTO_CsC *c)
{
    ...
\end{lstlisting}

Last but not least, the implementation has one notable performance improvement not mentioned in the redesigned protocols.
In various steps \gls{hkdf} is used multiple times in a row.
For example to derive the four blinding secrets $\alpha_0, \alpha_1, \beta_0, \beta_1$.
The derivation can be done in one \gls{hkdf} call with bigger output size, 128 bit in this case.
The output then can be split in four parts and then mapped to the ed25519 subgroup.
This can be done secure, because as explained in \autoref{sec:kdf} a \gls{hkdf} output is truly random.


\section{Taler Cryptographic Utilities}
\begin{bfhNoteBox}
    Implementation is done in Taler's exchange.
    From here on the implementation can be found in the exchange git repository \cite{taler-git:exchange}.
\end{bfhNoteBox}
The cryptographic utilities of Taler can be found in \texttt{src/util}.


The implementation is done in various locations:
\begin{itemize}
    \item \texttt{src/include/taler\_crypto\_lib.h}: This header file is included when using Taler's cryptography implementation.
    The different data structures and functionality are defined here.
    \item \texttt{src/util/denom.c}: Implement denomination utility functions for \gls{CSBS} cases
    \item \texttt{src/util/crypto.c}: Adjust all utility functions to support \gls{CSBS}.
    crypto.c contains many cryptographic utility functions, for example to create planchets or blinding factors.
    \item \texttt{src/util/test\_crypto.c}: Functionality tests for crypto.c and denom.c
    \item \texttt{src/include/taler\_signatures.h}: In this header file message formats and signature constants are defined (not modified)
    \item \texttt{src/util/secmod\_signatures.c}: Utility functions for Taler security module signatures
\end{itemize}

The security module \texttt{taler-secmod-cs} is implemented here:
\begin{itemize}
    \item \texttt{src/util/taler-exchange-secmod-cs.c}: Standalone process to perform private key Clause Blind Schnorr signature operations.
    \item \texttt{src/util/taler-exchange-secmod-cs.h}: Specification of \ac{IPC} messages for the CS secmod process
    \item \texttt{src/util/taler-exchange-secmod-cs.conf}: Configuration file for the secmod process
    \item \texttt{src/util/secmod\_common.c} and \texttt{src/util/secmod\_common.h}: Common functions for the exchange's security modules (not modified)
\end{itemize}

The corresponding crypto helper, that talks with the security module, and its tests \& benchmarks are implemented here:
\begin{itemize}
    \item \texttt{src/util/crypto\_helper\_cs.c}: Utility functions to communicate with the security module
    \item \texttt{src/util/crypto\_helper\_common.c}: and \texttt{crypto\_helper\_common.h}: Common functions for the exchange security modules (not modified)
    \item \texttt{src/util/test\_helper\_cs.c}: Tests and benchmarks for the \gls{CSBS} crypto helper
\end{itemize}
% Crypto API offene Punkte:
%Input-validation of points and scalars:
% describe clamping: https://neilmadden.blog/2020/05/28/whats-the-curve25519-clamping-all-about/
% Testing: inverse operations, blinded signature test


\section{Denomination Key Management}
For the implementation, the \gls{CSBS} security module had to be connected to the key handling and the \gls{CSBS} denominations had to be integrated:
\begin{itemize}
    \item \url{src/exchange/taler-exchange-httpd_keys.h} and \\
    \url{src/exchange/taler-exchange-httpd_keys.c}: Integrate \gls{CSBS} secmod and denomination key management
    \item \url{src/exchange-tools/taler-exchange-offline.c}: Implement \gls{CSBS} case for offline signing of denomination keys
    \item \url{src/include/taler_exchange_service.h}: \\
    Add \gls{CSBS} secmod public key to struct\\TALER\_EXCHANGE\_FutureKeys
    \item \url{src/json/json_helper.c}: Implement CS case in function parse\_denom\_pub (used in taler-exchange-offline.c)
    \item \url{src/json/json_pack.c}: Implement \gls{CSBS} case in function TALER\_JSON\_pack\_denom\_pub (used in taler-exchange-httpd\_keys.c)
    \item \url{src/pq/pq_query_helper.c}: Implement \gls{CSBS} case in function qconv\_denom\_pub
    \item \url{src/pq/pq_result_helper.c}: Implement \gls{CSBS} case in function extract\_denom\_pub
\end{itemize}

In order for the tests to pass, the following changes had to be implemented:
\begin{itemize}
    \item \url{src/lib/exchange_api_management_get_keys.c}: Add denom\_secmod\_cs\_public\_key JSON parsing, implement \gls{CSBS} case \\in function TALER\_EXCHANGE\_ManagementGetKeysHandle
    \item \url{src/testing/.gitignore}: Add paths where \gls{CSBS} keys are stored (secmod-helper)
    \item \url{src/testing/test_auditor_api.conf}: Add section taler-exchange-secmod-cs
    \item \url{src/testing/test_exchange_api_keys_cherry_picking.conf}: Add section taler-exchange-secmod-cs
    \item \url{src/testing/testing_api_helpers_exchange.c}: Add \gls{CSBS} secmod start and stop logic
\end{itemize}


\section{New Endpoint for $R$}
The new endpoint is available in the exchange's HTTP server under \url{/csr}.
It parses and checks the input, passes the request for derivation of the two $ R $'s down to the \gls{CSBS} security module and returns them to the requestor.
The implementation can be found in:
\begin{itemize}
    \item \url{src/exchange/taler-exchange-httpd.c}:
    Definition for the new endpoint, calls the function that handles \url{/csr} requests
    \item \url{src/exchange/taler-exchange-httpd_responses.h} and \\
    \url{src/exchange/taler-exchange-httpd_responses.c}: \\
    Added function TEH\_RESPONSE\_reply\_invalid\_denom\_cipher\_for\_operation that indicates a failure when the endpoint is called for a non-\gls{CSBS} denomination
    \item \url{src/exchange/taler-exchange-httpd_csr.h} and \\
    \url{src/exchange/taler-exchange-httpd_csr.c}: \\
    Implementation of the request handler for the new endpoint
    \item \url{src/exchange/taler-exchange-httpd_keys.h} and \\
    \url{src/exchange/taler-exchange-httpd_keys.c}: \\
    Additional function TEH\_keys\_denomination\_cs\_r\_pub that passes down the request to derive the $ R $ to the taler-exchange-secmod-cs helper
\end{itemize}

The tests that check the functionality of the procotols are defined in \url{src/testing/} and use code that calls the \ac{API} (located in \url{src/lib/}).
Since the new endpoint is used during withdrawing coins, testing for the \url{/csr} endpoint is integrated in these protocol tests.
Therefore, a call to the endpoint was implemented and later integrated into the calls to the withdraw-\ac{API}.
Code for calling the endpoint is located in these files:
\begin{itemize}
    \item \url{src/include/taler_exchange_service.h}: \\
    Header describing functions and data structures used in withdraw and refresh testing:
    \begin{itemize}
        \item struct TALER\_EXCHANGE\_CsRHandle: Handle containing request information
        \item struct TALER\_EXCHANGE\_CsRResponse: Response details
        \item function TALER\_EXCHANGE\_CsRCallback: Callback function to deliver the results (used in withdraw and refresh)
        \item function TALER\_EXCHANGE\_csr: Used to call endpoint
        \item function TALER\_EXCHANGE\_csr\_cancel: Used to free dynamically allocated resources
    \end{itemize}
    \item \url{src/lib/exchange_api_csr.c}: Implementation of \url{/csr} request
\end{itemize}


\section{Withdraw Protocol}
\label{sec:withdraw-protocol-impl}
Since this is an existing endpoint, it was adjusted to support \gls{CSBS}.
Mainly, the in- and output-handling had to be adjusted as described in section \ref{sec:specification-withdraw-public-api}, additional cipher checks for the denomination were added and the \gls{CSBS} for persisting the request in the database was implemented.
\\\\
An interesting part of the implementation is the check whether a nonce was already used for this denomination or not (step: $s \leftarrow \text{GetWithdraw}(n_w, D_p)$).
This step ensures that the same signature will always be returned for a certain nonce.
Using the same nonce for the same denomination twice without this check would lead to the same random value $r$.
This is due to derivation of $r := \text{HKDF}(256,n_w || d_s, \text{"r"})$.
An attacker could then immediately recover the secret key by the following equation: $(h' - h) * x \mod q = s -s' \mod q$ \cite{tibouchi:attacks-schnorr-nonce}.
There are popular examples of this vulnerability in Sony Playstation 3's or Bitcoins ECDSA implementation \cite{buchanan:ps3-ecdsa-vuln} \cite{wang:bitcoin-ecdsa-vuln}.
More details on how such a vulnerability can be exploited can be found in one of the author's blog posts \cite{gian:nonce-sense}.\\
The designed Taler protocols using \gls{CSBS} are preventing this attack by checking the nonce and return the previously generated signature.
Additionally the denomination's public key is included in this check to prevent another issue explained in section \ref{sec:taler-vuln}.\\
The check is implemented by persisting a hash value over $n_w$ and $D_p$.
On every withdrawal \texttt{check\_request\_idempotent()} is called, which checks whether the persisted hash matches with the current $n_w, D_p$ pair.


\begin{itemize}
    \item \url{src/exchange/taler-exchange-httpd_withdraw.c}: Implementation of \gls{CSBS} case for withdraw endpoint
    \item \url{src/exchange/taler-exchange-httpd_keys.c}: Implement \gls{CSBS} case in function \\
    TEH\_keys\_denomination\_sign (passes the signature creation down to the crypto helpers)
    \item \url{src/include/taler_json_lib.h} and \url{src/json/json_helper.c}: \\
    Add function TALER\_JSON\_spec\_blinded\_planchet
    \item \url{src/json/json_pack.c}: \\
    Implement \gls{CSBS} case in function\\ TALER\_JSON\_pack\_blinded\_denom\_sig
    \item \url{src/pq/pq_query_helper.c}: implement \gls{CSBS} case in functions qconv\_denom\_sig and qconv\_blinded\_denom\_sig
    \item \url{src/pq/pq_result_helper.c}: Implement \gls{CSBS} case in function extract\_blinded\_denom\_sig
\end{itemize}

For testing, the \gls{CSBS}-related data structures and procedures as well as the request to the additional endpoint \url{/csr} (before performing the actual withdrawal) were integrated:
\begin{itemize}
    \item \url{src/testing/test_exchange_api.c}: Add additional tests for \gls{CSBS} withdraw
    \item \url{src/include/taler_testing_lib.h}: Specification for functions \\
    TALER\_TESTING\_cmd\_withdraw\_cs\_amount and \\
    TALER\_TESTING\_cmd\_withdraw\_cs\_amount\_reuse\_key, add denomination cipher parameter to function TALER\_TESTING\_find\_pk
    \item \url{src/testing/testing_api_cmd_withdraw.c}: add functions \\
    TALER\_TESTING\_cmd\_withdraw\_cs\_amount and \\
    TALER\_TESTING\_cmd\_withdraw\_cs\_amount\_reuse\_key, implement \gls{CSBS}-specific logic for withdraw
    \item \url{src/testing/testing_api_helpers_exchange.c}:
    add cipher parameter to function TALER\_TESTING\_find\_pk
    \item \url{src/lib/exchange_api_withdraw.c}: Implement \gls{CSBS}-specific withdraw logic, integrate \url{/csr} request
    \item \url{src/lib/exchange_api_withdraw2.c}: implement \gls{CSBS} case
    \item \url{src/include/taler_json_lib.h} and \url{src/json/json_pack.c}: \\
    Add function TALER\_JSON\_pack\_blinded\_planchet
    \item \url{src/json/json_helper.c} implement \gls{CSBS} case in function parse\_blinded\_denom\_sig
\end{itemize}

\section{Deposit Protocol}
For deposit, only few changes were necessary because some of the required functionality has already been added for the previously implemented protocols, and only the coin signature verification is \gls{CSBS}-specific in this protocol.
\begin{itemize}
    \item \url{/src/exchange/taler-exchange-httpd_deposit.c}: Add check whether denomination cipher and denomination signature cipher are equal
    \item \url{/src/json/json_helper.c}: Implement \gls{CSBS} case in function parse\_denom\_sig
    \item \url{/src/pq/pq_result_helper.c}: Implement \gls{CSBS} case in function extract\_denom\_sig
\end{itemize}

Tests for deposit are implemented here:
\begin{itemize}
    \item \url{/src/testing/test_exchange_api.c}: Add tests (see "struct TALER\_TESTING\_Command\ spend\_cs[]") that spend \gls{CSBS} coins withdrawn in tests added for withdrawal
    \item \url{/src/json/json_pack.c}: Implement \gls{CSBS} case in function TALER\_JSON\_pack\_denom\_sig
\end{itemize}

\section{Fixing a Minor Security Issue in Taler's RSA Blind Signature Protocols}
\label{sec:taler-vuln}
While implementing the nonce check in the \gls{CSBS} protocol (see section \ref{sec:withdraw-protocol-impl}), a minor security issue in Taler's current RSA Blind Signature implementation was detected and fixed.
The issue was only in the implementation of the current RSA Blind Signature protocols, the fix for this scenario was already implemented in \gls{CSBS} since the beginning.

\subsection{Security Issue}
\label{sec:taler-vuln-desc}

The redesigned \gls{CSBS} protocols already include the denomination key in the nonce check, which fixes this issue (see \ref{sec:withdraw-protocol-schnorr}).
In the case of \gls{RSABS}, the current protocol includes an \gls{idempotence} check by persisting the hash value of the blinded coin $m'$.
On a withdrawal/refresh the \gls{idempotence} check compares if the hash value of $m'$ was seen in the past and returns the 'old' signature on a match.
This could lead to the following scenario:

\begin{enumerate}
    \item A broken wallet withdraws a coin with denomination $D_{p_{(1)}}$.
    \item The wallet sends a request to withdraw the same coin for denomination $D_{p_{(2)}}$.
    \item The exchange returns the signature for the denomination $D_{p_{(1)}}$ due to the \gls{idempotence} check.
    \item Since the exchange returned an invalid signature, the customer can file a complaint at the auditor.
    \item The auditor then has to investigate why the exchange returned invalid signatures.
    \item The auditor can disprove the complaint by querying the persisted hash used for the \gls{idempotence} check.
    With the associated denomination public key that is also persisted, the auditor can successfully verify the signature and thus prove that the exchange operated honestly.
\end{enumerate}

Including the denomination public key into the persisted hash for the \gls{idempotence} check solves this issue.
If a broken wallet now sends the same coin for more than one denomination, the exchange returns valid signatures in both cases.\\
While this is still an issue, this case is already handled nicely in Taler since this situation could also occur if a broken value tries to withdraw the same coin with two different blinding factors.

\subsection{Impact}
The impact of this security vulnerability is considered as very low.
An auditor investigating such an issue can simply retrace what happened by checking the persisted hash and associated denomination.
The impact of the issue is, that an auditor needs to investigate an issue, which can be prevented inside the protocol.
\\
In the previous section the client was considered a broken wallet.
While this could be done on purpose by malicious a customer, there is no real motivation for abusing this issue due the easy detection of an auditor.


\subsection{Fix}
Listing \ref{lst:rsa-idempotence} shows the code of calculating the hash for the idempotency check in the RSA case before it was fixed.
By trying to implement the \gls{CSBS} case, the question came up why the RSA case has not included the denomination key into the check.
After discussing this issue with Christian Grothoff, the conclusion was to include the denomination public key to prevent the discussed issue.

\begin{lstlisting}[style=bfh-c,language=C, caption={Idempotency check on RSA}, label={lst:rsa-idempotence}]
    enum GNUNET_GenericReturnValue
    TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet,
                        struct TALER_BlindedCoinHash *bch)
    {
      switch (blinded_planchet->cipher)
      {
      case TALER_DENOMINATION_RSA:
        GNUNET_CRYPTO_hash (
          blinded_planchet->details.rsa_blinded_planchet.blinded_msg,
          blinded_planchet->details.rsa_blinded_planchet.blinded_msg_size,
          &bch->hash);
        return GNUNET_OK;
      case TALER_DENOMINATION_CS:
      ...

\end{lstlisting}

The issue is fixed by adding a hash of the current denomination key into the calculation of the hash used in the \gls{idempotence} check.
The applied fix can be seen in listing \ref{lst:fixed-idempotence}.

\begin{lstlisting}[style=bfh-c,language=C, caption={Fixed idempotency check}, label={lst:fixed-idempotence}]
    enum GNUNET_GenericReturnValue
    TALER_coin_ev_hash (const struct TALER_BlindedPlanchet *blinded_planchet,
                        const struct TALER_DenominationHash *denom_hash,
                        struct TALER_BlindedCoinHash *bch)
    {
      switch (blinded_planchet->cipher)
      {
      case TALER_DENOMINATION_RSA:
        {
          struct GNUNET_HashContext *hash_context;
          hash_context = GNUNET_CRYPTO_hash_context_start ();

          GNUNET_CRYPTO_hash_context_read (hash_context,
                                           &denom_hash->hash,
                                           sizeof(denom_hash->hash));
          GNUNET_CRYPTO_hash_context_read (hash_context,
                                           blinded_planchet->details.
                                           rsa_blinded_planchet.blinded_msg,
                                           blinded_planchet->details.
                                           rsa_blinded_planchet.blinded_msg_size);
          GNUNET_CRYPTO_hash_context_finish (hash_context,
                                             &bch->hash);
          return GNUNET_OK;
        }
      case TALER_DENOMINATION_CS:
        {
          struct GNUNET_HashContext *hash_context;
          hash_context = GNUNET_CRYPTO_hash_context_start ();

          GNUNET_CRYPTO_hash_context_read (hash_context,
                                           &denom_hash->hash,
                                           sizeof(denom_hash->hash));
          GNUNET_CRYPTO_hash_context_read (hash_context,
                                           &blinded_planchet->details.
                                           cs_blinded_planchet.nonce,
                                           sizeof (blinded_planchet->details.
                                                   cs_blinded_planchet.nonce));
          GNUNET_CRYPTO_hash_context_finish (hash_context,
                                             &bch->hash);
          return GNUNET_OK;
        }
      default:
        GNUNET_break (0);
        return GNUNET_SYSERR;
      }
    }
\end{lstlisting}