summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorjsing <>2019-10-17 14:31:56 +0000
committerjsing <>2019-10-17 14:31:56 +0000
commit5005c768b214178dfda133906da127d8d4c0a5bd (patch)
treed4d1d31e3dd32330ddca0199ceba659dc7eecb99
parentf94e8cb1dd847cd2efa0211e711707fc705f11eb (diff)
downloadopenbsd-5005c768b214178dfda133906da127d8d4c0a5bd.tar.gz
openbsd-5005c768b214178dfda133906da127d8d4c0a5bd.tar.bz2
openbsd-5005c768b214178dfda133906da127d8d4c0a5bd.zip
Sync RSA_padding_check_PKCS1_OAEP_mgf1().
Update RSA_padding_check_PKCS1_OAEP_mgf1() with code from OpenSSL 1.1.1d (with some improvements/corrections to comments). This brings in code to make the padding check constant time. ok inoguchi@ tb@
-rw-r--r--src/lib/libcrypto/rsa/rsa_oaep.c175
1 files changed, 111 insertions, 64 deletions
diff --git a/src/lib/libcrypto/rsa/rsa_oaep.c b/src/lib/libcrypto/rsa/rsa_oaep.c
index 6b1760da60..e54600b094 100644
--- a/src/lib/libcrypto/rsa/rsa_oaep.c
+++ b/src/lib/libcrypto/rsa/rsa_oaep.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: rsa_oaep.c,v 1.32 2019/10/09 16:17:59 jsing Exp $ */ 1/* $OpenBSD: rsa_oaep.c,v 1.33 2019/10/17 14:31:56 jsing Exp $ */
2/* 2/*
3 * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. 3 * Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved.
4 * 4 *
@@ -79,6 +79,7 @@
79#include <openssl/rsa.h> 79#include <openssl/rsa.h>
80#include <openssl/sha.h> 80#include <openssl/sha.h>
81 81
82#include "constant_time_locl.h"
82#include "rsa_locl.h" 83#include "rsa_locl.h"
83 84
84int 85int
@@ -169,13 +170,11 @@ RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
169 const unsigned char *from, int flen, int num, const unsigned char *param, 170 const unsigned char *from, int flen, int num, const unsigned char *param,
170 int plen, const EVP_MD *md, const EVP_MD *mgf1md) 171 int plen, const EVP_MD *md, const EVP_MD *mgf1md)
171{ 172{
172 int i, dblen, mlen = -1; 173 int i, dblen = 0, mlen = -1, one_index = 0, msg_index;
173 const unsigned char *maskeddb; 174 unsigned int good = 0, found_one_byte, mask;
174 int lzero; 175 const unsigned char *maskedseed, *maskeddb;
175 unsigned char *db = NULL;
176 unsigned char seed[EVP_MAX_MD_SIZE], phash[EVP_MAX_MD_SIZE]; 176 unsigned char seed[EVP_MAX_MD_SIZE], phash[EVP_MAX_MD_SIZE];
177 unsigned char *padded_from; 177 unsigned char *db = NULL, *em = NULL;
178 int bad = 0;
179 int mdlen; 178 int mdlen;
180 179
181 if (md == NULL) 180 if (md == NULL)
@@ -184,88 +183,136 @@ RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
184 mgf1md = md; 183 mgf1md = md;
185 184
186 if ((mdlen = EVP_MD_size(md)) <= 0) 185 if ((mdlen = EVP_MD_size(md)) <= 0)
187 goto err; 186 return -1;
188 187
189 if (--num < 2 * mdlen + 1) 188 if (tlen <= 0 || flen <= 0)
190 /* 189 return -1;
191 * 'num' is the length of the modulus, i.e. does not depend
192 * on the particular ciphertext.
193 */
194 goto decoding_err;
195 190
196 lzero = num - flen; 191 /*
197 if (lzero < 0) { 192 * |num| is the length of the modulus; |flen| is the length of the
198 /* 193 * encoded message. Therefore, for any |from| that was obtained by
199 * signalling this error immediately after detection might allow 194 * decrypting a ciphertext, we must have |flen| <= |num|. Similarly,
200 * for side-channel attacks (e.g. timing if 'plen' is huge 195 * |num| >= 2 * |mdlen| + 2 must hold for the modulus irrespective
201 * -- cf. James H. Manger, "A Chosen Ciphertext Attack on RSA 196 * of the ciphertext, see PKCS #1 v2.2, section 7.1.2.
202 * Optimal Asymmetric Encryption Padding (OAEP) [...]", 197 * This does not leak any side-channel information.
203 * CRYPTO 2001), so we use a 'bad' flag 198 */
204 */ 199 if (num < flen || num < 2 * mdlen + 2) {
205 bad = 1; 200 RSAerror(RSA_R_OAEP_DECODING_ERROR);
206 lzero = 0; 201 return -1;
207 flen = num; /* don't overflow the memcpy to padded_from */
208 } 202 }
209 203
210 dblen = num - mdlen; 204 dblen = num - mdlen - 1;
211 if ((db = malloc(dblen + num)) == NULL) { 205 if ((db = malloc(dblen)) == NULL) {
212 RSAerror(ERR_R_MALLOC_FAILURE); 206 RSAerror(ERR_R_MALLOC_FAILURE);
213 return -1; 207 goto cleanup;
208 }
209 if ((em = malloc(num)) == NULL) {
210 RSAerror(ERR_R_MALLOC_FAILURE);
211 goto cleanup;
212 }
213
214 /*
215 * Caller is encouraged to pass zero-padded message created with
216 * BN_bn2binpad. Trouble is that since we can't read out of |from|'s
217 * bounds, it's impossible to have an invariant memory access pattern
218 * in case |from| was not zero-padded in advance.
219 */
220 for (from += flen, em += num, i = 0; i < num; i++) {
221 mask = ~constant_time_is_zero(flen);
222 flen -= 1 & mask;
223 from -= 1 & mask;
224 *--em = *from & mask;
214 } 225 }
226 from = em;
215 227
216 /* 228 /*
217 * Always do this zero-padding copy (even when lzero == 0) 229 * The first byte must be zero, however we must not leak if this is
218 * to avoid leaking timing info about the value of lzero. 230 * true. See James H. Manger, "A Chosen Ciphertext Attack on RSA
231 * Optimal Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001).
219 */ 232 */
220 padded_from = db + dblen; 233 good = constant_time_is_zero(from[0]);
221 memset(padded_from, 0, lzero);
222 memcpy(padded_from + lzero, from, flen);
223 234
224 maskeddb = padded_from + mdlen; 235 maskedseed = from + 1;
236 maskeddb = from + 1 + mdlen;
225 237
226 if (PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md)) 238 if (PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md))
227 goto err; 239 goto cleanup;
228 for (i = 0; i < mdlen; i++) 240 for (i = 0; i < mdlen; i++)
229 seed[i] ^= padded_from[i]; 241 seed[i] ^= maskedseed[i];
242
230 if (PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md)) 243 if (PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md))
231 goto err; 244 goto cleanup;
232 for (i = 0; i < dblen; i++) 245 for (i = 0; i < dblen; i++)
233 db[i] ^= maskeddb[i]; 246 db[i] ^= maskeddb[i];
234 247
235 if (!EVP_Digest((void *)param, plen, phash, NULL, md, NULL)) 248 if (!EVP_Digest((void *)param, plen, phash, NULL, md, NULL))
236 goto err; 249 goto cleanup;
237 250
238 if (timingsafe_memcmp(db, phash, mdlen) != 0 || bad) 251 good &= constant_time_is_zero(timingsafe_memcmp(db, phash, mdlen));
239 goto decoding_err; 252
240 else { 253 found_one_byte = 0;
241 for (i = mdlen; i < dblen; i++) 254 for (i = mdlen; i < dblen; i++) {
242 if (db[i] != 0x00) 255 /*
243 break; 256 * Padding consists of a number of 0-bytes, followed by a 1.
244 if (i == dblen || db[i] != 0x01) 257 */
245 goto decoding_err; 258 unsigned int equals1 = constant_time_eq(db[i], 1);
246 else { 259 unsigned int equals0 = constant_time_is_zero(db[i]);
247 /* everything looks OK */ 260
248 261 one_index = constant_time_select_int(~found_one_byte & equals1,
249 mlen = dblen - ++i; 262 i, one_index);
250 if (tlen < mlen) { 263 found_one_byte |= equals1;
251 RSAerror(RSA_R_DATA_TOO_LARGE); 264 good &= (found_one_byte | equals0);
252 mlen = -1; 265 }
253 } else 266
254 memcpy(to, db + i, mlen); 267 good &= found_one_byte;
255 } 268
269 /*
270 * At this point |good| is zero unless the plaintext was valid,
271 * so plaintext-awareness ensures timing side-channels are no longer a
272 * concern.
273 */
274 msg_index = one_index + 1;
275 mlen = dblen - msg_index;
276
277 /*
278 * For good measure, do this check in constant time as well.
279 */
280 good &= constant_time_ge(tlen, mlen);
281
282 /*
283 * Even though we can't fake result's length, we can pretend copying
284 * |tlen| bytes where |mlen| bytes would be real. The last |tlen| of
285 * |dblen| bytes are viewed as a circular buffer starting at |tlen|-|mlen'|,
286 * where |mlen'| is the "saturated" |mlen| value. Deducing information
287 * about failure or |mlen| would require an attacker to observe
288 * memory access patterns with byte granularity *as it occurs*. It
289 * should be noted that failure is indistinguishable from normal
290 * operation if |tlen| is fixed by protocol.
291 */
292 tlen = constant_time_select_int(constant_time_lt(dblen, tlen), dblen, tlen);
293 msg_index = constant_time_select_int(good, msg_index, dblen - tlen);
294 mlen = dblen - msg_index;
295 for (from = db + msg_index, mask = good, i = 0; i < tlen; i++) {
296 unsigned int equals = constant_time_eq(i, mlen);
297
298 from -= dblen & equals; /* if (i == mlen) rewind */
299 mask &= mask ^ equals; /* if (i == mlen) mask = 0 */
300 to[i] = constant_time_select_8(mask, from[i], to[i]);
256 } 301 }
257 free(db);
258 return mlen;
259 302
260 decoding_err:
261 /* 303 /*
262 * To avoid chosen ciphertext attacks, the error message should not 304 * To avoid chosen ciphertext attacks, the error message should not
263 * reveal which kind of decoding error happened 305 * reveal which kind of decoding error happened.
264 */ 306 */
265 RSAerror(RSA_R_OAEP_DECODING_ERROR); 307 RSAerror(RSA_R_OAEP_DECODING_ERROR);
266 err: 308 err_clear_last_constant_time(1 & good);
267 free(db); 309
268 return -1; 310 cleanup:
311 explicit_bzero(seed, sizeof(seed));
312 freezero(db, dblen);
313 freezero(em, num);
314
315 return constant_time_select_int(good, mlen, -1);
269} 316}
270 317
271int 318int