- const unsigned char *from, int flen, int num,
- const unsigned char *param, int plen)
- {
- int i, dblen, mlen = -1;
- const unsigned char *maskeddb;
- int lzero;
- unsigned char *db = NULL, seed[SHA_DIGEST_LENGTH], phash[SHA_DIGEST_LENGTH];
- int bad = 0;
-
- if (--num < 2 * SHA_DIGEST_LENGTH + 1)
- /* 'num' is the length of the modulus, i.e. does not depend on the
- * particular ciphertext. */
- goto decoding_err;
-
- lzero = num - flen;
- if (lzero < 0)
- {
- /* lzero == -1 */
-
- /* signalling this error immediately after detection might allow
- * for side-channel attacks (e.g. timing if 'plen' is huge
- * -- cf. James H. Manger, "A Chosen Ciphertext Attack on RSA Optimal
- * Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001),
- * so we use a 'bad' flag */
- bad = 1;
- lzero = 0;
- }
- maskeddb = from - lzero + SHA_DIGEST_LENGTH;
-
- dblen = num - SHA_DIGEST_LENGTH;
- db = OPENSSL_malloc(dblen);
- if (db == NULL)
- {
- RSAerr(RSA_F_RSA_PADDING_ADD_PKCS1_OAEP, ERR_R_MALLOC_FAILURE);
- return -1;
- }
-
- MGF1(seed, SHA_DIGEST_LENGTH, maskeddb, dblen);
- for (i = lzero; i < SHA_DIGEST_LENGTH; i++)
- seed[i] ^= from[i - lzero];
-
- MGF1(db, dblen, seed, SHA_DIGEST_LENGTH);
- for (i = 0; i < dblen; i++)
- db[i] ^= maskeddb[i];
-
- EVP_Digest((void *)param, plen, phash, NULL, EVP_sha1(), NULL);
-
- if (memcmp(db, phash, SHA_DIGEST_LENGTH) != 0 || bad)
- goto decoding_err;
- else
- {
- for (i = SHA_DIGEST_LENGTH; i < dblen; i++)
- if (db[i] != 0x00)
- break;
- if (db[i] != 0x01 || i++ >= dblen)
- goto decoding_err;
- else
- {
- /* everything looks OK */
-
- mlen = dblen - i;
- if (tlen < mlen)
- {
- RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, RSA_R_DATA_TOO_LARGE);
- mlen = -1;
- }
- else
- memcpy(to, db + i, mlen);
- }
- }
- OPENSSL_free(db);
- return mlen;
-
-decoding_err:
- /* to avoid chosen ciphertext attacks, the error message should not reveal
- * which kind of decoding error happened */
- RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP, RSA_R_OAEP_DECODING_ERROR);
- if (db != NULL) OPENSSL_free(db);
- return -1;
- }
-
-int MGF1(unsigned char *mask, long len,
- const unsigned char *seed, long seedlen)
- {
- long i, outlen = 0;
- unsigned char cnt[4];
- EVP_MD_CTX c;
- unsigned char md[SHA_DIGEST_LENGTH];
-
- EVP_MD_CTX_init(&c);
- for (i = 0; outlen < len; i++)
- {
- cnt[0] = (unsigned char)((i >> 24) & 255);
- cnt[1] = (unsigned char)((i >> 16) & 255);
- cnt[2] = (unsigned char)((i >> 8)) & 255;
- cnt[3] = (unsigned char)(i & 255);
- EVP_DigestInit_ex(&c,EVP_sha1(), NULL);
- EVP_DigestUpdate(&c, seed, seedlen);
- EVP_DigestUpdate(&c, cnt, 4);
- if (outlen + SHA_DIGEST_LENGTH <= len)
- {
- EVP_DigestFinal_ex(&c, mask + outlen, NULL);
- outlen += SHA_DIGEST_LENGTH;
- }
- else
- {
- EVP_DigestFinal_ex(&c, md, NULL);
- memcpy(mask + outlen, md, len - outlen);
- outlen = len;
- }
- }
- EVP_MD_CTX_cleanup(&c);
- return 0;
- }
-#endif
+ const unsigned char *from, int flen, int num,
+ const unsigned char *param, int plen)
+{
+ return RSA_padding_check_PKCS1_OAEP_mgf1(to, tlen, from, flen, num,
+ param, plen, NULL, NULL);
+}
+
+int RSA_padding_check_PKCS1_OAEP_mgf1(unsigned char *to, int tlen,
+ const unsigned char *from, int flen,
+ int num, const unsigned char *param,
+ int plen, const EVP_MD *md,
+ const EVP_MD *mgf1md)
+{
+ int i, dblen, mlen = -1, one_index = 0, msg_index;
+ unsigned int good, found_one_byte;
+ const unsigned char *maskedseed, *maskeddb;
+ /*
+ * |em| is the encoded message, zero-padded to exactly |num| bytes: em =
+ * Y || maskedSeed || maskedDB
+ */
+ unsigned char *db = NULL, *em = NULL, seed[EVP_MAX_MD_SIZE],
+ phash[EVP_MAX_MD_SIZE];
+ int mdlen;
+
+ if (md == NULL)
+ md = EVP_sha1();
+ if (mgf1md == NULL)
+ mgf1md = md;
+
+ mdlen = EVP_MD_size(md);
+
+ if (tlen <= 0 || flen <= 0)
+ return -1;
+ /*
+ * |num| is the length of the modulus; |flen| is the length of the
+ * encoded message. Therefore, for any |from| that was obtained by
+ * decrypting a ciphertext, we must have |flen| <= |num|. Similarly,
+ * num < 2 * mdlen + 2 must hold for the modulus irrespective of
+ * the ciphertext, see PKCS #1 v2.2, section 7.1.2.
+ * This does not leak any side-channel information.
+ */
+ if (num < flen || num < 2 * mdlen + 2)
+ goto decoding_err;
+
+ dblen = num - mdlen - 1;
+ db = OPENSSL_malloc(dblen);
+ em = OPENSSL_malloc(num);
+ if (db == NULL || em == NULL) {
+ RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, ERR_R_MALLOC_FAILURE);
+ goto cleanup;
+ }
+
+ /*
+ * Always do this zero-padding copy (even when num == flen) to avoid
+ * leaking that information. The copy still leaks some side-channel
+ * information, but it's impossible to have a fixed memory access
+ * pattern since we can't read out of the bounds of |from|.
+ *
+ * TODO(emilia): Consider porting BN_bn2bin_padded from BoringSSL.
+ */
+ memset(em, 0, num);
+ memcpy(em + num - flen, from, flen);
+
+ /*
+ * The first byte must be zero, however we must not leak if this is
+ * true. See James H. Manger, "A Chosen Ciphertext Attack on RSA
+ * Optimal Asymmetric Encryption Padding (OAEP) [...]", CRYPTO 2001).
+ */
+ good = constant_time_is_zero(em[0]);
+
+ maskedseed = em + 1;
+ maskeddb = em + 1 + mdlen;
+
+ if (PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md))
+ goto cleanup;
+ for (i = 0; i < mdlen; i++)
+ seed[i] ^= maskedseed[i];
+
+ if (PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md))
+ goto cleanup;
+ for (i = 0; i < dblen; i++)
+ db[i] ^= maskeddb[i];
+
+ if (!EVP_Digest((void *)param, plen, phash, NULL, md, NULL))
+ goto cleanup;
+
+ good &= constant_time_is_zero(CRYPTO_memcmp(db, phash, mdlen));
+
+ found_one_byte = 0;
+ for (i = mdlen; i < dblen; i++) {
+ /*
+ * Padding consists of a number of 0-bytes, followed by a 1.
+ */
+ unsigned int equals1 = constant_time_eq(db[i], 1);
+ unsigned int equals0 = constant_time_is_zero(db[i]);
+ one_index = constant_time_select_int(~found_one_byte & equals1,
+ i, one_index);
+ found_one_byte |= equals1;
+ good &= (found_one_byte | equals0);
+ }
+
+ good &= found_one_byte;
+
+ /*
+ * At this point |good| is zero unless the plaintext was valid,
+ * so plaintext-awareness ensures timing side-channels are no longer a
+ * concern.
+ */
+ if (!good)
+ goto decoding_err;
+
+ msg_index = one_index + 1;
+ mlen = dblen - msg_index;
+
+ if (tlen < mlen) {
+ RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1, RSA_R_DATA_TOO_LARGE);
+ mlen = -1;
+ } else {
+ memcpy(to, db + msg_index, mlen);
+ goto cleanup;
+ }
+
+ decoding_err:
+ /*
+ * To avoid chosen ciphertext attacks, the error message should not
+ * reveal which kind of decoding error happened.
+ */
+ RSAerr(RSA_F_RSA_PADDING_CHECK_PKCS1_OAEP_MGF1,
+ RSA_R_OAEP_DECODING_ERROR);
+ cleanup:
+ OPENSSL_free(db);
+ OPENSSL_free(em);
+ return mlen;
+}
+
+int PKCS1_MGF1(unsigned char *mask, long len,
+ const unsigned char *seed, long seedlen, const EVP_MD *dgst)
+{
+ long i, outlen = 0;
+ unsigned char cnt[4];
+ EVP_MD_CTX *c = EVP_MD_CTX_new();
+ unsigned char md[EVP_MAX_MD_SIZE];
+ int mdlen;
+ int rv = -1;
+
+ if (c == NULL)
+ goto err;
+ mdlen = EVP_MD_size(dgst);
+ if (mdlen < 0)
+ goto err;
+ for (i = 0; outlen < len; i++) {
+ cnt[0] = (unsigned char)((i >> 24) & 255);
+ cnt[1] = (unsigned char)((i >> 16) & 255);
+ cnt[2] = (unsigned char)((i >> 8)) & 255;
+ cnt[3] = (unsigned char)(i & 255);
+ if (!EVP_DigestInit_ex(c, dgst, NULL)
+ || !EVP_DigestUpdate(c, seed, seedlen)
+ || !EVP_DigestUpdate(c, cnt, 4))
+ goto err;
+ if (outlen + mdlen <= len) {
+ if (!EVP_DigestFinal_ex(c, mask + outlen, NULL))
+ goto err;
+ outlen += mdlen;
+ } else {
+ if (!EVP_DigestFinal_ex(c, md, NULL))
+ goto err;
+ memcpy(mask + outlen, md, len - outlen);
+ outlen = len;
+ }
+ }
+ rv = 0;
+ err:
+ EVP_MD_CTX_free(c);
+ return rv;
+}