Coverage Report

Created: 2025-11-16 06:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/nettle/pss.c
Line
Count
Source
1
/* pss.c
2
3
   PKCS#1 RSA-PSS padding (RFC-3447).
4
5
   Copyright (C) 2017 Daiki Ueno
6
7
   This file is part of GNU Nettle.
8
9
   GNU Nettle is free software: you can redistribute it and/or
10
   modify it under the terms of either:
11
12
     * the GNU Lesser General Public License as published by the Free
13
       Software Foundation; either version 3 of the License, or (at your
14
       option) any later version.
15
16
   or
17
18
     * the GNU General Public License as published by the Free
19
       Software Foundation; either version 2 of the License, or (at your
20
       option) any later version.
21
22
   or both in parallel, as here.
23
24
   GNU Nettle is distributed in the hope that it will be useful,
25
   but WITHOUT ANY WARRANTY; without even the implied warranty of
26
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27
   General Public License for more details.
28
29
   You should have received copies of the GNU General Public License and
30
   the GNU Lesser General Public License along with this program.  If
31
   not, see http://www.gnu.org/licenses/.
32
*/
33
34
#if HAVE_CONFIG_H
35
# include "config.h"
36
#endif
37
38
#include <assert.h>
39
#include <string.h>
40
41
#include "pss.h"
42
#include "pss-mgf1.h"
43
44
#include "bignum.h"
45
#include "gmp-glue.h"
46
47
#include "memxor.h"
48
#include "nettle-internal.h"
49
50
/* Masks to clear the leftmost N bits.  */
51
static const uint8_t pss_masks[8] = {
52
  0xFF, 0x7F, 0x3F, 0x1F, 0xF, 0x7, 0x3, 0x1
53
};
54
55
static const uint8_t pss_pad[8] = {0, 0, 0, 0, 0, 0, 0, 0};
56
57
/* Format the PKCS#1 PSS padding for given salt and digest, using
58
 * pss_mgf1() as the mask generation function.
59
 *
60
 * The encoded messsage is stored in M, and the consistency can be
61
 * checked with pss_verify_mgf1(), which takes the encoded message,
62
 * the length of salt, and the digest.  */
63
int
64
pss_encode_mgf1(mpz_t m, size_t bits,
65
    const struct nettle_hash *hash,
66
    size_t salt_length, const uint8_t *salt,
67
    const uint8_t *digest)
68
1.03k
{
69
1.03k
  TMP_GMP_DECL(em, uint8_t);
70
1.03k
  TMP_DECL_ALIGN(state, NETTLE_MAX_HASH_CONTEXT_SIZE);
71
1.03k
  size_t key_size = (bits + 7) / 8;
72
1.03k
  size_t j;
73
74
1.03k
  TMP_GMP_ALLOC(em, key_size);
75
1.03k
  TMP_ALLOC_ALIGN(state, hash->context_size);
76
77
1.03k
  if (key_size < hash->digest_size + salt_length + 2)
78
0
    {
79
0
      TMP_GMP_FREE(em);
80
0
      return 0;
81
0
    }
82
83
  /* Compute M'.  */
84
1.03k
  hash->init(state);
85
1.03k
  hash->update(state, sizeof(pss_pad), pss_pad);
86
1.03k
  hash->update(state, hash->digest_size, digest);
87
1.03k
  hash->update(state, salt_length, salt);
88
89
  /* Store H in EM, right after maskedDB.  */
90
1.03k
  hash->digest(state, hash->digest_size, em + key_size - hash->digest_size - 1);
91
92
  /* Compute dbMask.  */
93
1.03k
  hash->init(state);
94
1.03k
  hash->update(state, hash->digest_size, em + key_size - hash->digest_size - 1);
95
96
1.03k
  pss_mgf1(state, hash, key_size - hash->digest_size - 1, em);
97
98
  /* Compute maskedDB and store it in front of H in EM.  */
99
1.03k
  j = key_size - salt_length - hash->digest_size - 2;
100
101
1.03k
  em[j++] ^= 1;
102
1.03k
  memxor(em + j, salt, salt_length);
103
1.03k
  j += salt_length;
104
105
  /* Store the trailer field following H.  */
106
1.03k
  j += hash->digest_size;
107
1.03k
  em[j] = 0xbc;
108
109
  /* Clear the leftmost 8 * emLen - emBits of the leftmost octet in EM.  */
110
1.03k
  *em &= pss_masks[(8 * key_size - bits)];
111
112
1.03k
  nettle_mpz_set_str_256_u(m, key_size, em);
113
1.03k
  TMP_GMP_FREE(em);
114
1.03k
  return 1;
115
1.03k
}
116
117
/* Check the consistency of given PKCS#1 PSS encoded message, created
118
 * with pss_encode_mgf1().
119
 *
120
 * Returns 1 if the encoded message is consistent, 0 if it is
121
 * inconsistent.  */
122
int
123
pss_verify_mgf1(const mpz_t m, size_t bits,
124
    const struct nettle_hash *hash,
125
    size_t salt_length,
126
    const uint8_t *digest)
127
2.74k
{
128
2.74k
  TMP_GMP_DECL(em, uint8_t);
129
2.74k
  TMP_DECL(h2, uint8_t, NETTLE_MAX_HASH_DIGEST_SIZE);
130
2.74k
  TMP_DECL_ALIGN(state, NETTLE_MAX_HASH_CONTEXT_SIZE);
131
2.74k
  uint8_t *h, *db, *salt;
132
2.74k
  size_t key_size = (bits + 7) / 8;
133
2.74k
  size_t j;
134
2.74k
  int ret = 0;
135
136
  /* Allocate twice the key size to store the intermediate data DB
137
   * following the EM value.  */
138
2.74k
  TMP_GMP_ALLOC(em, key_size * 2);
139
140
2.74k
  TMP_ALLOC(h2, hash->digest_size);
141
2.74k
  TMP_ALLOC_ALIGN(state, hash->context_size);
142
143
2.74k
  if (key_size < hash->digest_size + salt_length + 2)
144
2
    goto cleanup;
145
146
2.73k
  if (mpz_sizeinbase(m, 2) > bits)
147
589
    goto cleanup;
148
149
2.15k
  nettle_mpz_get_str_256(key_size, em, m);
150
151
  /* Check the trailer field.  */
152
2.15k
  if (em[key_size - 1] != 0xbc)
153
2.05k
    goto cleanup;
154
155
  /* Extract H.  */
156
99
  h = em + (key_size - hash->digest_size - 1);
157
158
  /* The leftmost 8 * emLen - emBits bits of the leftmost octet of EM
159
   * must all equal to zero. Always true here, thanks to the above
160
   * check on the bit size of m. */
161
99
  assert((*em & ~pss_masks[(8 * key_size - bits)]) == 0);
162
163
  /* Compute dbMask.  */
164
99
  hash->init(state);
165
99
  hash->update(state, hash->digest_size, h);
166
167
99
  db = em + key_size;
168
99
  pss_mgf1(state, hash, key_size - hash->digest_size - 1, db);
169
170
  /* Compute DB.  */
171
99
  memxor(db, em, key_size - hash->digest_size - 1);
172
173
99
  *db &= pss_masks[(8 * key_size - bits)];
174
4.30k
  for (j = 0; j < key_size - salt_length - hash->digest_size - 2; j++)
175
4.27k
    if (db[j] != 0)
176
69
      goto cleanup;
177
178
  /* Check the octet right after PS is 0x1.  */
179
30
  if (db[j] != 0x1)
180
2
    goto cleanup;
181
28
  salt = db + j + 1;
182
183
  /* Compute H'.  */
184
28
  hash->init(state);
185
28
  hash->update(state, sizeof(pss_pad), pss_pad);
186
28
  hash->update(state, hash->digest_size, digest);
187
28
  hash->update(state, salt_length, salt);
188
28
  hash->digest(state, hash->digest_size, h2);
189
190
  /* Check if H' = H.  */
191
28
  if (memcmp(h2, h, hash->digest_size) != 0)
192
28
    goto cleanup;
193
194
0
  ret = 1;
195
2.74k
 cleanup:
196
2.74k
  TMP_GMP_FREE(em);
197
2.74k
  return ret;
198
0
}