Coverage Report

Created: 2022-06-23 06:44

/src/botan/src/lib/pk_pad/emsa_pssr/pssr.cpp
Line
Count
Source (jump to first uncovered line)
1
/*
2
* PSSR
3
* (C) 1999-2007,2017 Jack Lloyd
4
*
5
* Botan is released under the Simplified BSD License (see license.txt)
6
*/
7
8
#include <botan/internal/pssr.h>
9
#include <botan/exceptn.h>
10
#include <botan/rng.h>
11
#include <botan/internal/mgf1.h>
12
#include <botan/internal/bit_ops.h>
13
#include <botan/der_enc.h>
14
#include <botan/pk_keys.h>
15
#include <botan/internal/padding.h>
16
17
namespace Botan {
18
19
namespace {
20
21
/*
22
* PSSR Encode Operation
23
*/
24
secure_vector<uint8_t> pss_encode(HashFunction& hash,
25
                                  const secure_vector<uint8_t>& msg,
26
                                  const secure_vector<uint8_t>& salt,
27
                                  size_t output_bits)
28
0
   {
29
0
   const size_t HASH_SIZE = hash.output_length();
30
0
   const size_t SALT_SIZE = salt.size();
31
32
0
   if(msg.size() != HASH_SIZE)
33
0
      throw Encoding_Error("Cannot encode PSS string, input length invalid for hash");
34
0
   if(output_bits < 8*HASH_SIZE + 8*SALT_SIZE + 9)
35
0
      throw Encoding_Error("Cannot encode PSS string, output length too small");
36
37
0
   const size_t output_length = (output_bits + 7) / 8;
38
39
0
   for(size_t i = 0; i != 8; ++i)
40
0
      hash.update(0);
41
0
   hash.update(msg);
42
0
   hash.update(salt);
43
0
   secure_vector<uint8_t> H = hash.final();
44
45
0
   secure_vector<uint8_t> EM(output_length);
46
47
0
   EM[output_length - HASH_SIZE - SALT_SIZE - 2] = 0x01;
48
0
   buffer_insert(EM, output_length - 1 - HASH_SIZE - SALT_SIZE, salt);
49
0
   mgf1_mask(hash, H.data(), HASH_SIZE, EM.data(), output_length - HASH_SIZE - 1);
50
0
   EM[0] &= 0xFF >> (8 * ((output_bits + 7) / 8) - output_bits);
51
0
   buffer_insert(EM, output_length - 1 - HASH_SIZE, H);
52
0
   EM[output_length-1] = 0xBC;
53
0
   return EM;
54
0
   }
55
56
bool pss_verify(HashFunction& hash,
57
                const secure_vector<uint8_t>& pss_repr,
58
                const secure_vector<uint8_t>& message_hash,
59
                size_t key_bits,
60
                size_t* out_salt_size)
61
54
   {
62
54
   const size_t HASH_SIZE = hash.output_length();
63
54
   const size_t KEY_BYTES = (key_bits + 7) / 8;
64
65
54
   if(key_bits < 8*HASH_SIZE + 9)
66
2
      return false;
67
68
52
   if(message_hash.size() != HASH_SIZE)
69
0
      return false;
70
71
52
   if(pss_repr.size() > KEY_BYTES || pss_repr.size() <= 1)
72
2
      return false;
73
74
50
   if(pss_repr[pss_repr.size()-1] != 0xBC)
75
16
      return false;
76
77
34
   secure_vector<uint8_t> coded = pss_repr;
78
34
   if(coded.size() < KEY_BYTES)
79
26
      {
80
26
      secure_vector<uint8_t> temp(KEY_BYTES);
81
26
      buffer_insert(temp, KEY_BYTES - coded.size(), coded);
82
26
      coded = temp;
83
26
      }
84
85
34
   const size_t TOP_BITS = 8 * ((key_bits + 7) / 8) - key_bits;
86
34
   if(TOP_BITS > 8 - high_bit(coded[0]))
87
1
      return false;
88
89
33
   uint8_t* DB = coded.data();
90
33
   const size_t DB_size = coded.size() - HASH_SIZE - 1;
91
92
33
   const uint8_t* H = &coded[DB_size];
93
33
   const size_t H_size = HASH_SIZE;
94
95
33
   mgf1_mask(hash, H, H_size, DB, DB_size);
96
33
   DB[0] &= 0xFF >> TOP_BITS;
97
98
33
   size_t salt_offset = 0;
99
46
   for(size_t j = 0; j != DB_size; ++j)
100
45
      {
101
45
      if(DB[j] == 0x01)
102
12
         { salt_offset = j + 1; break; }
103
33
      if(DB[j])
104
20
         return false;
105
33
      }
106
13
   if(salt_offset == 0)
107
1
      return false;
108
109
12
   const size_t salt_size = DB_size - salt_offset;
110
111
108
   for(size_t j = 0; j != 8; ++j)
112
96
      hash.update(0);
113
12
   hash.update(message_hash);
114
12
   hash.update(&DB[salt_offset], salt_size);
115
116
12
   const secure_vector<uint8_t> H2 = hash.final();
117
118
12
   const bool ok = constant_time_compare(H, H2.data(), HASH_SIZE);
119
120
12
   if(out_salt_size && ok)
121
0
      *out_salt_size = salt_size;
122
123
12
   return ok;
124
13
   }
125
126
}
127
128
PSSR::PSSR(std::unique_ptr<HashFunction> hash) :
129
   m_hash(std::move(hash)),
130
   m_salt_size(m_hash->output_length()),
131
   m_required_salt_len(false)
132
0
   {
133
0
   }
134
135
PSSR::PSSR(std::unique_ptr<HashFunction> hash, size_t salt_size) :
136
   m_hash(std::move(hash)),
137
   m_salt_size(salt_size),
138
   m_required_salt_len(true)
139
56
   {
140
56
   }
141
142
/*
143
* PSSR Update Operation
144
*/
145
void PSSR::update(const uint8_t input[], size_t length)
146
56
   {
147
56
   m_hash->update(input, length);
148
56
   }
149
150
/*
151
* Return the raw (unencoded) data
152
*/
153
secure_vector<uint8_t> PSSR::raw_data()
154
56
   {
155
56
   return m_hash->final();
156
56
   }
157
158
secure_vector<uint8_t> PSSR::encoding_of(const secure_vector<uint8_t>& msg,
159
                                         size_t output_bits,
160
                                         RandomNumberGenerator& rng)
161
0
   {
162
0
   const secure_vector<uint8_t> salt = rng.random_vec(m_salt_size);
163
0
   return pss_encode(*m_hash, msg, salt, output_bits);
164
0
   }
165
166
/*
167
* PSSR Decode/Verify Operation
168
*/
169
bool PSSR::verify(const secure_vector<uint8_t>& coded,
170
                  const secure_vector<uint8_t>& raw,
171
                  size_t key_bits)
172
54
   {
173
54
   size_t salt_size = 0;
174
54
   const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
175
176
54
   if(m_required_salt_len && salt_size != m_salt_size)
177
54
      return false;
178
179
0
   return ok;
180
54
   }
181
182
std::unique_ptr<EMSA> PSSR::new_object()
183
0
   {
184
0
   return std::make_unique<PSSR>(m_hash->new_object(), m_salt_size);
185
0
   }
186
187
std::string PSSR::name() const
188
0
   {
189
0
   return "EMSA4(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
190
0
   }
191
192
AlgorithmIdentifier PSSR::config_for_x509(const Private_Key& key,
193
                                          const std::string& cert_hash_name) const
194
0
   {
195
0
   if(cert_hash_name != m_hash->name())
196
0
      throw Invalid_Argument("Hash function from opts and hash_fn argument"
197
0
         " need to be identical");
198
   // check that the signature algorithm and the padding scheme fit
199
0
   if(!sig_algo_and_pad_ok(key.algo_name(), "EMSA4"))
200
0
      {
201
0
      throw Invalid_Argument("Encoding scheme with canonical name EMSA4"
202
0
         " not supported for signature algorithm " + key.algo_name());
203
0
      }
204
205
0
   const AlgorithmIdentifier hash_id(cert_hash_name, AlgorithmIdentifier::USE_NULL_PARAM);
206
0
   const AlgorithmIdentifier mgf_id("MGF1", hash_id.BER_encode());
207
208
0
   std::vector<uint8_t> parameters;
209
0
   DER_Encoder(parameters)
210
0
      .start_sequence()
211
0
      .start_context_specific(0).encode(hash_id).end_cons()
212
0
      .start_context_specific(1).encode(mgf_id).end_cons()
213
0
      .start_context_specific(2).encode(m_salt_size).end_cons()
214
0
      .start_context_specific(3).encode(size_t(1)).end_cons() // trailer field
215
0
      .end_cons();
216
217
   // hardcoded as RSA is the only valid algorithm for EMSA4 at the moment
218
0
   return AlgorithmIdentifier("RSA/EMSA4", parameters);
219
0
   }
220
221
PSSR_Raw::PSSR_Raw(std::unique_ptr<HashFunction> hash) :
222
   m_hash(std::move(hash)),
223
   m_salt_size(m_hash->output_length()),
224
   m_required_salt_len(false)
225
0
   {
226
0
   }
227
228
PSSR_Raw::PSSR_Raw(std::unique_ptr<HashFunction> hash, size_t salt_size) :
229
   m_hash(std::move(hash)),
230
   m_salt_size(salt_size),
231
   m_required_salt_len(true)
232
0
   {
233
0
   }
234
235
/*
236
* PSSR_Raw Update Operation
237
*/
238
void PSSR_Raw::update(const uint8_t input[], size_t length)
239
0
   {
240
0
   m_msg.insert(m_msg.end(), input, input + length);
241
0
   }
242
243
/*
244
* Return the raw (unencoded) data
245
*/
246
secure_vector<uint8_t> PSSR_Raw::raw_data()
247
0
   {
248
0
   secure_vector<uint8_t> ret;
249
0
   std::swap(ret, m_msg);
250
251
0
   if(ret.size() != m_hash->output_length())
252
0
      throw Encoding_Error("PSSR_Raw Bad input length, did not match hash");
253
254
0
   return ret;
255
0
   }
256
257
secure_vector<uint8_t> PSSR_Raw::encoding_of(const secure_vector<uint8_t>& msg,
258
                                             size_t output_bits,
259
                                             RandomNumberGenerator& rng)
260
0
   {
261
0
   secure_vector<uint8_t> salt = rng.random_vec(m_salt_size);
262
0
   return pss_encode(*m_hash, msg, salt, output_bits);
263
0
   }
264
265
/*
266
* PSSR_Raw Decode/Verify Operation
267
*/
268
bool PSSR_Raw::verify(const secure_vector<uint8_t>& coded,
269
                      const secure_vector<uint8_t>& raw,
270
                      size_t key_bits)
271
0
   {
272
0
   size_t salt_size = 0;
273
0
   const bool ok = pss_verify(*m_hash, coded, raw, key_bits, &salt_size);
274
275
0
   if(m_required_salt_len && salt_size != m_salt_size)
276
0
      return false;
277
278
0
   return ok;
279
0
   }
280
281
std::unique_ptr<EMSA> PSSR_Raw::new_object()
282
0
   {
283
0
   return std::make_unique<PSSR_Raw>(m_hash->new_object(), m_salt_size);
284
0
   }
285
286
std::string PSSR_Raw::name() const
287
0
   {
288
0
   return "PSSR_Raw(" + m_hash->name() + ",MGF1," + std::to_string(m_salt_size) + ")";
289
0
   }
290
291
}