summaryrefslogtreecommitdiffstats
path: root/src/crypto/rsa
diff options
context:
space:
mode:
Diffstat (limited to 'src/crypto/rsa')
-rw-r--r--src/crypto/rsa/CMakeLists.txt4
-rw-r--r--src/crypto/rsa/blinding.c24
-rw-r--r--src/crypto/rsa/internal.h34
-rw-r--r--src/crypto/rsa/padding.c110
-rw-r--r--src/crypto/rsa/rsa.c143
-rw-r--r--src/crypto/rsa/rsa_asn1.c421
-rw-r--r--src/crypto/rsa/rsa_impl.c311
-rw-r--r--src/crypto/rsa/rsa_test.c511
-rw-r--r--src/crypto/rsa/rsa_test.cc869
9 files changed, 1667 insertions, 760 deletions
diff --git a/src/crypto/rsa/CMakeLists.txt b/src/crypto/rsa/CMakeLists.txt
index 0ea12c8..bd8ad3b 100644
--- a/src/crypto/rsa/CMakeLists.txt
+++ b/src/crypto/rsa/CMakeLists.txt
@@ -1,4 +1,4 @@
-include_directories(. .. ../../include)
+include_directories(../../include)
add_library(
rsa
@@ -15,7 +15,7 @@ add_library(
add_executable(
rsa_test
- rsa_test.c
+ rsa_test.cc
$<TARGET_OBJECTS:test_support>
)
diff --git a/src/crypto/rsa/blinding.c b/src/crypto/rsa/blinding.c
index 245142b..c93cee1 100644
--- a/src/crypto/rsa/blinding.c
+++ b/src/crypto/rsa/blinding.c
@@ -137,7 +137,7 @@ BN_BLINDING *BN_BLINDING_new(const BIGNUM *A, const BIGNUM *Ai, BIGNUM *mod) {
ret = (BN_BLINDING*) OPENSSL_malloc(sizeof(BN_BLINDING));
if (ret == NULL) {
- OPENSSL_PUT_ERROR(RSA, BN_BLINDING_new, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return NULL;
}
memset(ret, 0, sizeof(BN_BLINDING));
@@ -190,7 +190,7 @@ int BN_BLINDING_update(BN_BLINDING *b, BN_CTX *ctx) {
int ret = 0;
if (b->A == NULL || b->Ai == NULL) {
- OPENSSL_PUT_ERROR(RSA, BN_BLINDING_update, RSA_R_BN_NOT_INITIALIZED);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED);
goto err;
}
@@ -230,7 +230,7 @@ int BN_BLINDING_convert_ex(BIGNUM *n, BIGNUM *r, BN_BLINDING *b, BN_CTX *ctx) {
int ret = 1;
if (b->A == NULL || b->Ai == NULL) {
- OPENSSL_PUT_ERROR(RSA, BN_BLINDING_convert_ex, RSA_R_BN_NOT_INITIALIZED);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED);
return 0;
}
@@ -266,7 +266,7 @@ int BN_BLINDING_invert_ex(BIGNUM *n, const BIGNUM *r, BN_BLINDING *b,
ret = BN_mod_mul(n, n, r, b->mod, ctx);
} else {
if (b->Ai == NULL) {
- OPENSSL_PUT_ERROR(RSA, BN_BLINDING_invert_ex, RSA_R_BN_NOT_INITIALIZED);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BN_NOT_INITIALIZED);
return 0;
}
ret = BN_mod_mul(n, n, b->Ai, b->mod, ctx);
@@ -325,13 +325,13 @@ BN_BLINDING *BN_BLINDING_create_param(
if (!BN_rand_range(ret->A, ret->mod)) {
goto err;
}
- if (BN_mod_inverse(ret->Ai, ret->A, ret->mod, ctx) == NULL) {
+
+ int no_inverse;
+ if (BN_mod_inverse_ex(ret->Ai, &no_inverse, ret->A, ret->mod, ctx) == NULL) {
/* this should almost never happen for good RSA keys */
- uint32_t error = ERR_peek_last_error();
- if (ERR_GET_REASON(error) == BN_R_NO_INVERSE) {
+ if (no_inverse) {
if (retry_counter-- == 0) {
- OPENSSL_PUT_ERROR(RSA, BN_BLINDING_create_param,
- RSA_R_TOO_MANY_ITERATIONS);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_MANY_ITERATIONS);
goto err;
}
ERR_clear_error();
@@ -416,14 +416,14 @@ BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx) {
BN_CTX_start(ctx);
e = BN_CTX_get(ctx);
if (e == NULL) {
- OPENSSL_PUT_ERROR(RSA, rsa_setup_blinding, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
if (rsa->e == NULL) {
e = rsa_get_public_exp(rsa->d, rsa->p, rsa->q, ctx);
if (e == NULL) {
- OPENSSL_PUT_ERROR(RSA, rsa_setup_blinding, RSA_R_NO_PUBLIC_EXPONENT);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_NO_PUBLIC_EXPONENT);
goto err;
}
} else {
@@ -444,7 +444,7 @@ BN_BLINDING *rsa_setup_blinding(RSA *rsa, BN_CTX *in_ctx) {
ret = BN_BLINDING_create_param(NULL, e, n, ctx, rsa->meth->bn_mod_exp,
mont_ctx);
if (ret == NULL) {
- OPENSSL_PUT_ERROR(RSA, rsa_setup_blinding, ERR_R_BN_LIB);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB);
goto err;
}
diff --git a/src/crypto/rsa/internal.h b/src/crypto/rsa/internal.h
index d15f2a5..c0044c3 100644
--- a/src/crypto/rsa/internal.h
+++ b/src/crypto/rsa/internal.h
@@ -59,8 +59,6 @@
#include <openssl/base.h>
-#include <openssl/asn1.h>
-
#if defined(__cplusplus)
extern "C" {
@@ -109,8 +107,6 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned to_len,
const EVP_MD *md, const EVP_MD *mgf1md);
int RSA_padding_add_none(uint8_t *to, unsigned to_len, const uint8_t *from,
unsigned from_len);
-int RSA_padding_check_none(uint8_t *to, unsigned to_len, const uint8_t *from,
- unsigned from_len);
/* RSA_private_transform calls either the method-specific |private_transform|
* function (if given) or the generic one. See the comment for
@@ -118,20 +114,26 @@ int RSA_padding_check_none(uint8_t *to, unsigned to_len, const uint8_t *from,
int RSA_private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
size_t len);
-typedef struct rsa_pss_params_st {
- X509_ALGOR *hashAlgorithm;
- X509_ALGOR *maskGenAlgorithm;
- ASN1_INTEGER *saltLength;
- ASN1_INTEGER *trailerField;
-} RSA_PSS_PARAMS;
-DECLARE_ASN1_FUNCTIONS(RSA_PSS_PARAMS)
+/* RSA_additional_prime contains information about the third, forth etc prime
+ * in a multi-prime RSA key. */
+typedef struct RSA_additional_prime_st {
+ BIGNUM *prime;
+ /* exp is d^{prime-1} mod prime */
+ BIGNUM *exp;
+ /* coeff is such that r×coeff ≡ 1 mod prime. */
+ BIGNUM *coeff;
+
+ /* Values below here are not in the ASN.1 serialisation. */
+
+ /* r is the product of all primes (including p and q) prior to this one. */
+ BIGNUM *r;
+ /* method_mod is managed by the |RSA_METHOD|. */
+ BN_MONT_CTX *method_mod;
+} RSA_additional_prime;
+
+void RSA_additional_prime_free(RSA_additional_prime *ap);
-typedef struct rsa_oaep_params_st {
- X509_ALGOR *hashFunc;
- X509_ALGOR *maskGenFunc;
- X509_ALGOR *pSourceFunc;
-} RSA_OAEP_PARAMS;
#if defined(__cplusplus)
} /* extern C */
diff --git a/src/crypto/rsa/padding.c b/src/crypto/rsa/padding.c
index 0a725f1..5a42e24 100644
--- a/src/crypto/rsa/padding.c
+++ b/src/crypto/rsa/padding.c
@@ -74,14 +74,12 @@ int RSA_padding_add_PKCS1_type_1(uint8_t *to, unsigned tlen,
uint8_t *p;
if (tlen < RSA_PKCS1_PADDING_SIZE) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_type_1,
- RSA_R_KEY_SIZE_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
if (flen > tlen - RSA_PKCS1_PADDING_SIZE) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_type_1,
- RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
}
@@ -105,15 +103,13 @@ int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned tlen,
const uint8_t *p;
if (flen < 2) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
- RSA_R_DATA_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_SMALL);
return -1;
}
p = from;
if ((*(p++) != 0) || (*(p++) != 1)) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
- RSA_R_BLOCK_TYPE_IS_NOT_01);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BLOCK_TYPE_IS_NOT_01);
return -1;
}
@@ -126,8 +122,7 @@ int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned tlen,
p++;
break;
} else {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
- RSA_R_BAD_FIXED_HEADER_DECRYPT);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_FIXED_HEADER_DECRYPT);
return -1;
}
}
@@ -135,21 +130,18 @@ int RSA_padding_check_PKCS1_type_1(uint8_t *to, unsigned tlen,
}
if (i == j) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
- RSA_R_NULL_BEFORE_BLOCK_MISSING);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_NULL_BEFORE_BLOCK_MISSING);
return -1;
}
if (i < 8) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
- RSA_R_BAD_PAD_BYTE_COUNT);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_PAD_BYTE_COUNT);
return -1;
}
i++; /* Skip over the '\0' */
j -= i;
if (j > tlen) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_1,
- RSA_R_DATA_TOO_LARGE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE);
return -1;
}
memcpy(to, p, j);
@@ -163,14 +155,12 @@ int RSA_padding_add_PKCS1_type_2(uint8_t *to, unsigned tlen,
uint8_t *p;
if (tlen < RSA_PKCS1_PADDING_SIZE) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_type_2,
- RSA_R_KEY_SIZE_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
if (flen > tlen - RSA_PKCS1_PADDING_SIZE) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_type_2,
- RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
}
@@ -271,8 +261,7 @@ int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned tlen,
size_t msg_index, msg_len;
if (flen == 0) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
- RSA_R_EMPTY_PUBLIC_KEY);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY);
return -1;
}
@@ -281,8 +270,7 @@ int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned tlen,
* |RSA_PKCS1_PADDING| make it impossible to completely avoid Bleichenbacher's
* attack. */
if (!RSA_message_index_PKCS1_type_2(from, flen, &msg_index)) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
- RSA_R_PKCS_DECODING_ERROR);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR);
return -1;
}
@@ -290,8 +278,7 @@ int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned tlen,
if (msg_len > tlen) {
/* This shouldn't happen because this function is always called with |tlen|
* the key size and |flen| is bounded by the key size. */
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_type_2,
- RSA_R_PKCS_DECODING_ERROR);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR);
return -1;
}
memcpy(to, &from[msg_index], msg_len);
@@ -300,14 +287,12 @@ int RSA_padding_check_PKCS1_type_2(uint8_t *to, unsigned tlen,
int RSA_padding_add_none(uint8_t *to, unsigned tlen, const uint8_t *from, unsigned flen) {
if (flen > tlen) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_none,
- RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
}
if (flen < tlen) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_none,
- RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE);
return 0;
}
@@ -315,17 +300,6 @@ int RSA_padding_add_none(uint8_t *to, unsigned tlen, const uint8_t *from, unsign
return 1;
}
-int RSA_padding_check_none(uint8_t *to, unsigned tlen, const uint8_t *from,
- unsigned flen) {
- if (flen > tlen) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_none, RSA_R_DATA_TOO_LARGE);
- return -1;
- }
-
- memcpy(to, from, flen);
- return flen;
-}
-
int PKCS1_MGF1(uint8_t *mask, unsigned len, const uint8_t *seed,
unsigned seedlen, const EVP_MD *dgst) {
unsigned outlen = 0;
@@ -388,21 +362,18 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen,
mdlen = EVP_MD_size(md);
if (tlen < 2 * mdlen + 2) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
- RSA_R_KEY_SIZE_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
emlen = tlen - 1;
if (flen > emlen - 2 * mdlen - 1) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
- RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
}
if (emlen < 2 * mdlen + 1) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
- RSA_R_KEY_SIZE_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
@@ -422,8 +393,7 @@ int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen,
dbmask = OPENSSL_malloc(emlen - mdlen);
if (dbmask == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_OAEP_mgf1,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return 0;
}
@@ -477,8 +447,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen,
dblen = flen - mdlen - 1;
db = OPENSSL_malloc(dblen);
if (db == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_OAEP_mgf1,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -526,8 +495,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen,
one_index++;
mlen = dblen - one_index;
if (tlen < mlen) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_OAEP_mgf1,
- RSA_R_DATA_TOO_LARGE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE);
mlen = -1;
} else {
memcpy(to, db + one_index, mlen);
@@ -539,8 +507,7 @@ int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *to, unsigned tlen,
decoding_err:
/* to avoid chosen ciphertext attacks, the error message should not reveal
* which kind of decoding error happened */
- OPENSSL_PUT_ERROR(RSA, RSA_padding_check_PKCS1_OAEP_mgf1,
- RSA_R_OAEP_DECODING_ERROR);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_OAEP_DECODING_ERROR);
err:
OPENSSL_free(db);
return -1;
@@ -576,15 +543,14 @@ int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
} else if (sLen == -2) {
sLen = -2;
} else if (sLen < -2) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_SLEN_CHECK_FAILED);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED);
goto err;
}
MSBits = (BN_num_bits(rsa->n) - 1) & 0x7;
emLen = RSA_size(rsa);
if (EM[0] & (0xFF << MSBits)) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1,
- RSA_R_FIRST_OCTET_INVALID);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_FIRST_OCTET_INVALID);
goto err;
}
if (MSBits == 0) {
@@ -593,18 +559,18 @@ int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
}
if (emLen < ((int)hLen + sLen + 2)) {
/* sLen can be small negative */
- OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_DATA_TOO_LARGE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE);
goto err;
}
if (EM[emLen - 1] != 0xbc) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_LAST_OCTET_INVALID);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_LAST_OCTET_INVALID);
goto err;
}
maskedDBLen = emLen - hLen - 1;
H = EM + maskedDBLen;
DB = OPENSSL_malloc(maskedDBLen);
if (!DB) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
if (PKCS1_MGF1(DB, maskedDBLen, H, hLen, mgf1Hash) < 0) {
@@ -620,12 +586,11 @@ int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
;
}
if (DB[i++] != 0x1) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1,
- RSA_R_SLEN_RECOVERY_FAILED);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_RECOVERY_FAILED);
goto err;
}
if (sLen >= 0 && (maskedDBLen - i) != sLen) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_SLEN_CHECK_FAILED);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED);
goto err;
}
if (!EVP_DigestInit_ex(&ctx, Hash, NULL) ||
@@ -642,7 +607,7 @@ int RSA_verify_PKCS1_PSS_mgf1(RSA *rsa, const uint8_t *mHash,
goto err;
}
if (memcmp(H_, H, hLen)) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify_PKCS1_PSS_mgf1, RSA_R_BAD_SIGNATURE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE);
ret = 0;
} else {
ret = 1;
@@ -681,14 +646,12 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
} else if (sLen == -2) {
sLen = -2;
} else if (sLen < -2) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
- RSA_R_SLEN_CHECK_FAILED);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_SLEN_CHECK_FAILED);
goto err;
}
if (BN_is_zero(rsa->n)) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
- RSA_R_EMPTY_PUBLIC_KEY);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY);
goto err;
}
@@ -701,21 +664,18 @@ int RSA_padding_add_PKCS1_PSS_mgf1(RSA *rsa, unsigned char *EM,
}
if (sLen == -2) {
if (emLen < hLen + 2) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
- RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
goto err;
}
sLen = emLen - hLen - 2;
} else if (emLen < hLen + sLen + 2) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
- RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
goto err;
}
if (sLen > 0) {
salt = OPENSSL_malloc(sLen);
if (!salt) {
- OPENSSL_PUT_ERROR(RSA, RSA_padding_add_PKCS1_PSS_mgf1,
- ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
if (!RAND_bytes(salt, sLen)) {
diff --git a/src/crypto/rsa/rsa.c b/src/crypto/rsa/rsa.c
index 17059b0..2f23165 100644
--- a/src/crypto/rsa/rsa.c
+++ b/src/crypto/rsa/rsa.c
@@ -79,7 +79,7 @@ RSA *RSA_new(void) { return RSA_new_method(NULL); }
RSA *RSA_new_method(const ENGINE *engine) {
RSA *rsa = (RSA *)OPENSSL_malloc(sizeof(RSA));
if (rsa == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_new_method, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return NULL;
}
@@ -114,6 +114,18 @@ RSA *RSA_new_method(const ENGINE *engine) {
return rsa;
}
+void RSA_additional_prime_free(RSA_additional_prime *ap) {
+ if (ap == NULL) {
+ return;
+ }
+
+ BN_clear_free(ap->prime);
+ BN_clear_free(ap->exp);
+ BN_clear_free(ap->coeff);
+ BN_clear_free(ap->r);
+ OPENSSL_free(ap);
+}
+
void RSA_free(RSA *rsa) {
unsigned u;
@@ -145,6 +157,10 @@ void RSA_free(RSA *rsa) {
}
OPENSSL_free(rsa->blindings);
OPENSSL_free(rsa->blindings_inuse);
+ if (rsa->additional_primes != NULL) {
+ sk_RSA_additional_prime_pop_free(rsa->additional_primes,
+ RSA_additional_prime_free);
+ }
CRYPTO_MUTEX_cleanup(&rsa->lock);
OPENSSL_free(rsa);
}
@@ -162,6 +178,16 @@ int RSA_generate_key_ex(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
return RSA_default_method.keygen(rsa, bits, e_value, cb);
}
+int RSA_generate_multi_prime_key(RSA *rsa, int bits, int num_primes,
+ BIGNUM *e_value, BN_GENCB *cb) {
+ if (rsa->meth->multi_prime_keygen) {
+ return rsa->meth->multi_prime_keygen(rsa, bits, num_primes, e_value, cb);
+ }
+
+ return RSA_default_method.multi_prime_keygen(rsa, bits, num_primes, e_value,
+ cb);
+}
+
int RSA_encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
const uint8_t *in, size_t in_len, int padding) {
if (rsa->meth->encrypt) {
@@ -342,20 +368,15 @@ static const struct pkcs1_sig_prefix kPKCS1SigPrefixes[] = {
},
};
-/* TODO(fork): mostly new code, needs careful review. */
-
-/* pkcs1_prefixed_msg builds a PKCS#1, prefixed version of |msg| for the given
- * hash function and sets |out_msg| to point to it. On successful return,
- * |*out_msg| may be allocated memory and, if so, |*is_alloced| will be 1. */
-static int pkcs1_prefixed_msg(uint8_t **out_msg, size_t *out_msg_len,
- int *is_alloced, int hash_nid, const uint8_t *msg,
- size_t msg_len) {
+int RSA_add_pkcs1_prefix(uint8_t **out_msg, size_t *out_msg_len,
+ int *is_alloced, int hash_nid, const uint8_t *msg,
+ size_t msg_len) {
unsigned i;
if (hash_nid == NID_md5_sha1) {
/* Special case: SSL signature, just check the length. */
if (msg_len != SSL_SIG_LENGTH) {
- OPENSSL_PUT_ERROR(RSA, pkcs1_prefixed_msg, RSA_R_INVALID_MESSAGE_LENGTH);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
@@ -378,13 +399,13 @@ static int pkcs1_prefixed_msg(uint8_t **out_msg, size_t *out_msg_len,
signed_msg_len = prefix_len + msg_len;
if (signed_msg_len < prefix_len) {
- OPENSSL_PUT_ERROR(RSA, pkcs1_prefixed_msg, RSA_R_TOO_LONG);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_TOO_LONG);
return 0;
}
signed_msg = OPENSSL_malloc(signed_msg_len);
if (!signed_msg) {
- OPENSSL_PUT_ERROR(RSA, pkcs1_prefixed_msg, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return 0;
}
@@ -398,7 +419,7 @@ static int pkcs1_prefixed_msg(uint8_t **out_msg, size_t *out_msg_len,
return 1;
}
- OPENSSL_PUT_ERROR(RSA, pkcs1_prefixed_msg, RSA_R_UNKNOWN_ALGORITHM_TYPE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_ALGORITHM_TYPE);
return 0;
}
@@ -415,14 +436,14 @@ int RSA_sign(int hash_nid, const uint8_t *in, unsigned in_len, uint8_t *out,
return rsa->meth->sign(hash_nid, in, in_len, out, out_len, rsa);
}
- if (!pkcs1_prefixed_msg(&signed_msg, &signed_msg_len, &signed_msg_is_alloced,
- hash_nid, in, in_len)) {
+ if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len,
+ &signed_msg_is_alloced, hash_nid, in, in_len)) {
return 0;
}
if (rsa_size < RSA_PKCS1_PADDING_SIZE ||
signed_msg_len > rsa_size - RSA_PKCS1_PADDING_SIZE) {
- OPENSSL_PUT_ERROR(RSA, RSA_sign, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DIGEST_TOO_BIG_FOR_RSA_KEY);
goto finish;
}
@@ -453,18 +474,18 @@ int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
}
if (sig_len != rsa_size) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify, RSA_R_WRONG_SIGNATURE_LENGTH);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_WRONG_SIGNATURE_LENGTH);
return 0;
}
if (hash_nid == NID_md5_sha1 && msg_len != SSL_SIG_LENGTH) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify, RSA_R_INVALID_MESSAGE_LENGTH);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_INVALID_MESSAGE_LENGTH);
return 0;
}
buf = OPENSSL_malloc(rsa_size);
if (!buf) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return 0;
}
@@ -473,13 +494,13 @@ int RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len,
goto out;
}
- if (!pkcs1_prefixed_msg(&signed_msg, &signed_msg_len, &signed_msg_is_alloced,
- hash_nid, msg, msg_len)) {
+ if (!RSA_add_pkcs1_prefix(&signed_msg, &signed_msg_len,
+ &signed_msg_is_alloced, hash_nid, msg, msg_len)) {
goto out;
}
if (len != signed_msg_len || CRYPTO_memcmp(buf, signed_msg, len) != 0) {
- OPENSSL_PUT_ERROR(RSA, RSA_verify, RSA_R_BAD_SIGNATURE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_SIGNATURE);
goto out;
}
@@ -509,12 +530,12 @@ int RSA_check_key(const RSA *key) {
}
if ((key->p != NULL) != (key->q != NULL)) {
- OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_ONLY_ONE_OF_P_Q_GIVEN);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_ONLY_ONE_OF_P_Q_GIVEN);
return 0;
}
if (!key->n || !key->e) {
- OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_VALUE_MISSING);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
return 0;
}
@@ -526,7 +547,7 @@ int RSA_check_key(const RSA *key) {
ctx = BN_CTX_new();
if (ctx == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_check_key, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return 0;
}
@@ -540,52 +561,74 @@ int RSA_check_key(const RSA *key) {
BN_init(&dmq1);
BN_init(&iqmp);
- if (/* n = pq */
- !BN_mul(&n, key->p, key->q, ctx) ||
- /* lcm = lcm(p-1, q-1) */
+ if (!BN_mul(&n, key->p, key->q, ctx) ||
+ /* lcm = lcm(prime-1, for all primes) */
!BN_sub(&pm1, key->p, BN_value_one()) ||
!BN_sub(&qm1, key->q, BN_value_one()) ||
!BN_mul(&lcm, &pm1, &qm1, ctx) ||
+ !BN_gcd(&gcd, &pm1, &qm1, ctx)) {
+ OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
+ goto out;
+ }
+
+ size_t num_additional_primes = 0;
+ if (key->additional_primes != NULL) {
+ num_additional_primes = sk_RSA_additional_prime_num(key->additional_primes);
+ }
+
+ size_t i;
+ for (i = 0; i < num_additional_primes; i++) {
+ const RSA_additional_prime *ap =
+ sk_RSA_additional_prime_value(key->additional_primes, i);
+ if (!BN_mul(&n, &n, ap->prime, ctx) ||
+ !BN_sub(&pm1, ap->prime, BN_value_one()) ||
+ !BN_mul(&lcm, &lcm, &pm1, ctx) ||
+ !BN_gcd(&gcd, &gcd, &pm1, ctx)) {
+ OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
+ goto out;
+ }
+ }
+
+ if (!BN_div(&lcm, NULL, &lcm, &gcd, ctx) ||
!BN_gcd(&gcd, &pm1, &qm1, ctx) ||
- !BN_div(&lcm, NULL, &lcm, &gcd, ctx) ||
- /* de = d*e mod lcm(p-1, q-1) */
+ /* de = d*e mod lcm(prime-1, for all primes). */
!BN_mod_mul(&de, key->d, key->e, &lcm, ctx)) {
- OPENSSL_PUT_ERROR(RSA, RSA_check_key, ERR_LIB_BN);
+ OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
goto out;
}
if (BN_cmp(&n, key->n) != 0) {
- OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_N_NOT_EQUAL_P_Q);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_N_NOT_EQUAL_P_Q);
goto out;
}
if (!BN_is_one(&de)) {
- OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_D_E_NOT_CONGRUENT_TO_1);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_D_E_NOT_CONGRUENT_TO_1);
goto out;
}
has_crt_values = key->dmp1 != NULL;
if (has_crt_values != (key->dmq1 != NULL) ||
has_crt_values != (key->iqmp != NULL)) {
- OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_INCONSISTENT_SET_OF_CRT_VALUES);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_INCONSISTENT_SET_OF_CRT_VALUES);
goto out;
}
- if (has_crt_values) {
+ if (has_crt_values && num_additional_primes == 0) {
if (/* dmp1 = d mod (p-1) */
!BN_mod(&dmp1, key->d, &pm1, ctx) ||
/* dmq1 = d mod (q-1) */
!BN_mod(&dmq1, key->d, &qm1, ctx) ||
/* iqmp = q^-1 mod p */
!BN_mod_inverse(&iqmp, key->q, key->p, ctx)) {
- OPENSSL_PUT_ERROR(RSA, RSA_check_key, ERR_LIB_BN);
+ OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
goto out;
}
if (BN_cmp(&dmp1, key->dmp1) != 0 ||
BN_cmp(&dmq1, key->dmq1) != 0 ||
BN_cmp(&iqmp, key->iqmp) != 0) {
- OPENSSL_PUT_ERROR(RSA, RSA_check_key, RSA_R_CRT_VALUES_INCORRECT);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_VALUES_INCORRECT);
goto out;
}
}
@@ -613,13 +656,17 @@ int RSA_recover_crt_params(RSA *rsa) {
int ok = 0;
if (rsa->n == NULL || rsa->e == NULL || rsa->d == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, RSA_R_EMPTY_PUBLIC_KEY);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY);
return 0;
}
if (rsa->p || rsa->q || rsa->dmp1 || rsa->dmq1 || rsa->iqmp) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params,
- RSA_R_CRT_PARAMS_ALREADY_GIVEN);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_CRT_PARAMS_ALREADY_GIVEN);
+ return 0;
+ }
+
+ if (rsa->additional_primes != NULL) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_CANNOT_RECOVER_MULTI_PRIME_KEY);
return 0;
}
@@ -628,7 +675,7 @@ int RSA_recover_crt_params(RSA *rsa) {
ctx = BN_CTX_new();
if (ctx == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
return 0;
}
@@ -641,7 +688,7 @@ int RSA_recover_crt_params(RSA *rsa) {
if (totient == NULL || rem == NULL || multiple == NULL || p_plus_q == NULL ||
p_minus_q == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -669,12 +716,12 @@ int RSA_recover_crt_params(RSA *rsa) {
!BN_div(multiple, NULL, totient, rsa->n, ctx) ||
!BN_add_word(multiple, 1) ||
!BN_div(totient, rem, totient, multiple, ctx)) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_BN_LIB);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB);
goto err;
}
if (!BN_is_zero(rem)) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, RSA_R_BAD_RSA_PARAMETERS);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_RSA_PARAMETERS);
goto err;
}
@@ -685,7 +732,7 @@ int RSA_recover_crt_params(RSA *rsa) {
rsa->iqmp = BN_new();
if (rsa->p == NULL || rsa->q == NULL || rsa->dmp1 == NULL || rsa->dmq1 ==
NULL || rsa->iqmp == NULL) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -703,12 +750,12 @@ int RSA_recover_crt_params(RSA *rsa) {
!BN_rshift1(rsa->q, rsa->q) ||
!BN_div(rsa->p, NULL, rsa->n, rsa->q, ctx) ||
!BN_mul(multiple, rsa->p, rsa->q, ctx)) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_BN_LIB);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB);
goto err;
}
if (BN_cmp(multiple, rsa->n) != 0) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, RSA_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_INTERNAL_ERROR);
goto err;
}
@@ -717,7 +764,7 @@ int RSA_recover_crt_params(RSA *rsa) {
!BN_sub(rem, rsa->q, BN_value_one()) ||
!BN_mod(rsa->dmq1, rsa->d, rem, ctx) ||
!BN_mod_inverse(rsa->iqmp, rsa->q, rsa->p, ctx)) {
- OPENSSL_PUT_ERROR(RSA, RSA_recover_crt_params, ERR_R_BN_LIB);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_BN_LIB);
goto err;
}
diff --git a/src/crypto/rsa/rsa_asn1.c b/src/crypto/rsa/rsa_asn1.c
index 924cb8a..e3756ba 100644
--- a/src/crypto/rsa/rsa_asn1.c
+++ b/src/crypto/rsa/rsa_asn1.c
@@ -55,45 +55,384 @@
#include <openssl/rsa.h>
+#include <assert.h>
+#include <limits.h>
+#include <string.h>
+
#include <openssl/asn1.h>
#include <openssl/asn1t.h>
+#include <openssl/bn.h>
+#include <openssl/bytestring.h>
+#include <openssl/err.h>
+#include <openssl/mem.h>
#include "internal.h"
-/* Override the default free and new methods */
-static int rsa_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it,
- void *exarg) {
- if (operation == ASN1_OP_NEW_PRE) {
- *pval = (ASN1_VALUE *)RSA_new();
- if (*pval) {
- return 2;
+static int parse_integer_buggy(CBS *cbs, BIGNUM **out, int buggy) {
+ assert(*out == NULL);
+ *out = BN_new();
+ if (*out == NULL) {
+ return 0;
+ }
+ if (buggy) {
+ return BN_cbs2unsigned_buggy(cbs, *out);
+ }
+ return BN_cbs2unsigned(cbs, *out);
+}
+
+static int parse_integer(CBS *cbs, BIGNUM **out) {
+ return parse_integer_buggy(cbs, out, 0 /* not buggy */);
+}
+
+static int marshal_integer(CBB *cbb, BIGNUM *bn) {
+ if (bn == NULL) {
+ /* An RSA object may be missing some components. */
+ OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
+ return 0;
+ }
+ return BN_bn2cbb(cbb, bn);
+}
+
+static RSA *parse_public_key(CBS *cbs, int buggy) {
+ RSA *ret = RSA_new();
+ if (ret == NULL) {
+ return NULL;
+ }
+ CBS child;
+ if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
+ !parse_integer_buggy(&child, &ret->n, buggy) ||
+ !parse_integer(&child, &ret->e) ||
+ CBS_len(&child) != 0) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+ RSA_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+RSA *RSA_parse_public_key(CBS *cbs) {
+ return parse_public_key(cbs, 0 /* not buggy */);
+}
+
+RSA *RSA_parse_public_key_buggy(CBS *cbs) {
+ /* Estonian IDs issued between September 2014 to September 2015 are
+ * broken. See https://crbug.com/532048 and https://crbug.com/534766.
+ *
+ * TODO(davidben): Remove this code and callers in March 2016. */
+ return parse_public_key(cbs, 1 /* buggy */);
+}
+
+RSA *RSA_public_key_from_bytes(const uint8_t *in, size_t in_len) {
+ CBS cbs;
+ CBS_init(&cbs, in, in_len);
+ RSA *ret = RSA_parse_public_key(&cbs);
+ if (ret == NULL || CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+ RSA_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+int RSA_marshal_public_key(CBB *cbb, const RSA *rsa) {
+ CBB child;
+ if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) ||
+ !marshal_integer(&child, rsa->n) ||
+ !marshal_integer(&child, rsa->e) ||
+ !CBB_flush(cbb)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+ return 0;
+ }
+ return 1;
+}
+
+int RSA_public_key_to_bytes(uint8_t **out_bytes, size_t *out_len,
+ const RSA *rsa) {
+ CBB cbb;
+ CBB_zero(&cbb);
+ if (!CBB_init(&cbb, 0) ||
+ !RSA_marshal_public_key(&cbb, rsa) ||
+ !CBB_finish(&cbb, out_bytes, out_len)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+ CBB_cleanup(&cbb);
+ return 0;
+ }
+ return 1;
+}
+
+/* kVersionTwoPrime and kVersionMulti are the supported values of the version
+ * field of an RSAPrivateKey structure (RFC 3447). */
+static const uint64_t kVersionTwoPrime = 0;
+static const uint64_t kVersionMulti = 1;
+
+/* rsa_parse_additional_prime parses a DER-encoded OtherPrimeInfo from |cbs| and
+ * advances |cbs|. It returns a newly-allocated |RSA_additional_prime| on
+ * success or NULL on error. The |r| and |method_mod| fields of the result are
+ * set to NULL. */
+static RSA_additional_prime *rsa_parse_additional_prime(CBS *cbs) {
+ RSA_additional_prime *ret = OPENSSL_malloc(sizeof(RSA_additional_prime));
+ if (ret == NULL) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+ return 0;
+ }
+ memset(ret, 0, sizeof(RSA_additional_prime));
+
+ CBS child;
+ if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
+ !parse_integer(&child, &ret->prime) ||
+ !parse_integer(&child, &ret->exp) ||
+ !parse_integer(&child, &ret->coeff) ||
+ CBS_len(&child) != 0) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+ RSA_additional_prime_free(ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+RSA *RSA_parse_private_key(CBS *cbs) {
+ BN_CTX *ctx = NULL;
+ BIGNUM *product_of_primes_so_far = NULL;
+ RSA *ret = RSA_new();
+ if (ret == NULL) {
+ return NULL;
+ }
+
+ CBS child;
+ uint64_t version;
+ if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
+ !CBS_get_asn1_uint64(&child, &version) ||
+ (version != kVersionTwoPrime && version != kVersionMulti) ||
+ !parse_integer(&child, &ret->n) ||
+ !parse_integer(&child, &ret->e) ||
+ !parse_integer(&child, &ret->d) ||
+ !parse_integer(&child, &ret->p) ||
+ !parse_integer(&child, &ret->q) ||
+ !parse_integer(&child, &ret->dmp1) ||
+ !parse_integer(&child, &ret->dmq1) ||
+ !parse_integer(&child, &ret->iqmp)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_VERSION);
+ goto err;
+ }
+
+ /* Multi-prime RSA requires a newer version. */
+ if (version == kVersionMulti &&
+ CBS_peek_asn1_tag(&child, CBS_ASN1_SEQUENCE)) {
+ CBS other_prime_infos;
+ if (!CBS_get_asn1(&child, &other_prime_infos, CBS_ASN1_SEQUENCE) ||
+ CBS_len(&other_prime_infos) == 0) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+ goto err;
+ }
+ ret->additional_primes = sk_RSA_additional_prime_new_null();
+ if (ret->additional_primes == NULL) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+
+ ctx = BN_CTX_new();
+ product_of_primes_so_far = BN_new();
+ if (ctx == NULL ||
+ product_of_primes_so_far == NULL ||
+ !BN_mul(product_of_primes_so_far, ret->p, ret->q, ctx)) {
+ goto err;
+ }
+
+ while (CBS_len(&other_prime_infos) > 0) {
+ RSA_additional_prime *ap = rsa_parse_additional_prime(&other_prime_infos);
+ if (ap == NULL) {
+ goto err;
+ }
+ if (!sk_RSA_additional_prime_push(ret->additional_primes, ap)) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+ RSA_additional_prime_free(ap);
+ goto err;
+ }
+ ap->r = BN_dup(product_of_primes_so_far);
+ if (ap->r == NULL ||
+ !BN_mul(product_of_primes_so_far, product_of_primes_so_far,
+ ap->prime, ctx)) {
+ goto err;
+ }
}
+ }
+
+ if (CBS_len(&child) != 0) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+ goto err;
+ }
+
+ BN_CTX_free(ctx);
+ BN_free(product_of_primes_so_far);
+ return ret;
+
+err:
+ BN_CTX_free(ctx);
+ BN_free(product_of_primes_so_far);
+ RSA_free(ret);
+ return NULL;
+}
+
+RSA *RSA_private_key_from_bytes(const uint8_t *in, size_t in_len) {
+ CBS cbs;
+ CBS_init(&cbs, in, in_len);
+ RSA *ret = RSA_parse_private_key(&cbs);
+ if (ret == NULL || CBS_len(&cbs) != 0) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
+ RSA_free(ret);
+ return NULL;
+ }
+ return ret;
+}
+
+int RSA_marshal_private_key(CBB *cbb, const RSA *rsa) {
+ const int is_multiprime =
+ sk_RSA_additional_prime_num(rsa->additional_primes) > 0;
+
+ CBB child;
+ if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) ||
+ !CBB_add_asn1_uint64(&child,
+ is_multiprime ? kVersionMulti : kVersionTwoPrime) ||
+ !marshal_integer(&child, rsa->n) ||
+ !marshal_integer(&child, rsa->e) ||
+ !marshal_integer(&child, rsa->d) ||
+ !marshal_integer(&child, rsa->p) ||
+ !marshal_integer(&child, rsa->q) ||
+ !marshal_integer(&child, rsa->dmp1) ||
+ !marshal_integer(&child, rsa->dmq1) ||
+ !marshal_integer(&child, rsa->iqmp)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+ return 0;
+ }
+
+ if (is_multiprime) {
+ CBB other_prime_infos;
+ if (!CBB_add_asn1(&child, &other_prime_infos, CBS_ASN1_SEQUENCE)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+ return 0;
+ }
+ size_t i;
+ for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) {
+ RSA_additional_prime *ap =
+ sk_RSA_additional_prime_value(rsa->additional_primes, i);
+ CBB other_prime_info;
+ if (!CBB_add_asn1(&other_prime_infos, &other_prime_info,
+ CBS_ASN1_SEQUENCE) ||
+ !marshal_integer(&other_prime_info, ap->prime) ||
+ !marshal_integer(&other_prime_info, ap->exp) ||
+ !marshal_integer(&other_prime_info, ap->coeff)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+ return 0;
+ }
+ }
+ }
+
+ if (!CBB_flush(cbb)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
return 0;
- } else if (operation == ASN1_OP_FREE_PRE) {
- RSA_free((RSA *)*pval);
- *pval = NULL;
- return 2;
}
return 1;
}
-ASN1_SEQUENCE_cb(RSAPrivateKey, rsa_cb) = {
- ASN1_SIMPLE(RSA, version, LONG),
- ASN1_SIMPLE(RSA, n, BIGNUM),
- ASN1_SIMPLE(RSA, e, BIGNUM),
- ASN1_SIMPLE(RSA, d, BIGNUM),
- ASN1_SIMPLE(RSA, p, BIGNUM),
- ASN1_SIMPLE(RSA, q, BIGNUM),
- ASN1_SIMPLE(RSA, dmp1, BIGNUM),
- ASN1_SIMPLE(RSA, dmq1, BIGNUM),
- ASN1_SIMPLE(RSA, iqmp, BIGNUM),
-} ASN1_SEQUENCE_END_cb(RSA, RSAPrivateKey);
+int RSA_private_key_to_bytes(uint8_t **out_bytes, size_t *out_len,
+ const RSA *rsa) {
+ CBB cbb;
+ CBB_zero(&cbb);
+ if (!CBB_init(&cbb, 0) ||
+ !RSA_marshal_private_key(&cbb, rsa) ||
+ !CBB_finish(&cbb, out_bytes, out_len)) {
+ OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
+ CBB_cleanup(&cbb);
+ return 0;
+ }
+ return 1;
+}
-ASN1_SEQUENCE_cb(RSAPublicKey, rsa_cb) = {
- ASN1_SIMPLE(RSA, n, BIGNUM),
- ASN1_SIMPLE(RSA, e, BIGNUM),
-} ASN1_SEQUENCE_END_cb(RSA, RSAPublicKey);
+RSA *d2i_RSAPublicKey(RSA **out, const uint8_t **inp, long len) {
+ if (len < 0) {
+ return NULL;
+ }
+ CBS cbs;
+ CBS_init(&cbs, *inp, (size_t)len);
+ RSA *ret = RSA_parse_public_key(&cbs);
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (out != NULL) {
+ RSA_free(*out);
+ *out = ret;
+ }
+ *inp += (size_t)len - CBS_len(&cbs);
+ return ret;
+}
+
+int i2d_RSAPublicKey(const RSA *in, uint8_t **outp) {
+ uint8_t *der;
+ size_t der_len;
+ if (!RSA_public_key_to_bytes(&der, &der_len, in)) {
+ return -1;
+ }
+ if (der_len > INT_MAX) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
+ OPENSSL_free(der);
+ return -1;
+ }
+ if (outp != NULL) {
+ if (*outp == NULL) {
+ *outp = der;
+ der = NULL;
+ } else {
+ memcpy(*outp, der, der_len);
+ *outp += der_len;
+ }
+ }
+ OPENSSL_free(der);
+ return (int)der_len;
+}
+
+RSA *d2i_RSAPrivateKey(RSA **out, const uint8_t **inp, long len) {
+ if (len < 0) {
+ return NULL;
+ }
+ CBS cbs;
+ CBS_init(&cbs, *inp, (size_t)len);
+ RSA *ret = RSA_parse_private_key(&cbs);
+ if (ret == NULL) {
+ return NULL;
+ }
+ if (out != NULL) {
+ RSA_free(*out);
+ *out = ret;
+ }
+ *inp += (size_t)len - CBS_len(&cbs);
+ return ret;
+}
+
+int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp) {
+ uint8_t *der;
+ size_t der_len;
+ if (!RSA_private_key_to_bytes(&der, &der_len, in)) {
+ return -1;
+ }
+ if (der_len > INT_MAX) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
+ OPENSSL_free(der);
+ return -1;
+ }
+ if (outp != NULL) {
+ if (*outp == NULL) {
+ *outp = der;
+ der = NULL;
+ } else {
+ memcpy(*outp, der, der_len);
+ *outp += der_len;
+ }
+ }
+ OPENSSL_free(der);
+ return (int)der_len;
+}
ASN1_SEQUENCE(RSA_PSS_PARAMS) = {
ASN1_EXP_OPT(RSA_PSS_PARAMS, hashAlgorithm, X509_ALGOR,0),
@@ -104,22 +443,24 @@ ASN1_SEQUENCE(RSA_PSS_PARAMS) = {
IMPLEMENT_ASN1_FUNCTIONS(RSA_PSS_PARAMS);
-ASN1_SEQUENCE(RSA_OAEP_PARAMS) = {
- ASN1_EXP_OPT(RSA_OAEP_PARAMS, hashFunc, X509_ALGOR, 0),
- ASN1_EXP_OPT(RSA_OAEP_PARAMS, maskGenFunc, X509_ALGOR, 1),
- ASN1_EXP_OPT(RSA_OAEP_PARAMS, pSourceFunc, X509_ALGOR, 2),
-} ASN1_SEQUENCE_END(RSA_OAEP_PARAMS);
-
-IMPLEMENT_ASN1_FUNCTIONS(RSA_OAEP_PARAMS);
-
-IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(RSA, RSAPrivateKey, RSAPrivateKey);
-
-IMPLEMENT_ASN1_ENCODE_FUNCTIONS_const_fname(RSA, RSAPublicKey, RSAPublicKey);
-
RSA *RSAPublicKey_dup(const RSA *rsa) {
- return ASN1_item_dup(ASN1_ITEM_rptr(RSAPublicKey), (RSA *) rsa);
+ uint8_t *der;
+ size_t der_len;
+ if (!RSA_public_key_to_bytes(&der, &der_len, rsa)) {
+ return NULL;
+ }
+ RSA *ret = RSA_public_key_from_bytes(der, der_len);
+ OPENSSL_free(der);
+ return ret;
}
RSA *RSAPrivateKey_dup(const RSA *rsa) {
- return ASN1_item_dup(ASN1_ITEM_rptr(RSAPrivateKey), (RSA *) rsa);
+ uint8_t *der;
+ size_t der_len;
+ if (!RSA_private_key_to_bytes(&der, &der_len, rsa)) {
+ return NULL;
+ }
+ RSA *ret = RSA_private_key_from_bytes(der, der_len);
+ OPENSSL_free(der);
+ return ret;
}
diff --git a/src/crypto/rsa/rsa_impl.c b/src/crypto/rsa/rsa_impl.c
index e14f0f5..eb4a36f 100644
--- a/src/crypto/rsa/rsa_impl.c
+++ b/src/crypto/rsa/rsa_impl.c
@@ -78,6 +78,15 @@ static int finish(RSA *rsa) {
BN_MONT_CTX_free(rsa->_method_mod_p);
BN_MONT_CTX_free(rsa->_method_mod_q);
+ if (rsa->additional_primes != NULL) {
+ size_t i;
+ for (i = 0; i < sk_RSA_additional_prime_num(rsa->additional_primes); i++) {
+ RSA_additional_prime *ap =
+ sk_RSA_additional_prime_value(rsa->additional_primes, i);
+ BN_MONT_CTX_free(ap->method_mod);
+ }
+ }
+
return 1;
}
@@ -94,24 +103,24 @@ static int encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
int i, ret = 0;
if (rsa_size > OPENSSL_RSA_MAX_MODULUS_BITS) {
- OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_MODULUS_TOO_LARGE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE);
return 0;
}
if (max_out < rsa_size) {
- OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
if (BN_ucmp(rsa->n, rsa->e) <= 0) {
- OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_BAD_E_VALUE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
return 0;
}
/* for large moduli, enforce exponent limit */
if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS &&
BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) {
- OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_BAD_E_VALUE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
return 0;
}
@@ -125,7 +134,7 @@ static int encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
result = BN_CTX_get(ctx);
buf = OPENSSL_malloc(rsa_size);
if (!f || !result || !buf) {
- OPENSSL_PUT_ERROR(RSA, encrypt, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -142,7 +151,7 @@ static int encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
i = RSA_padding_add_none(buf, rsa_size, in, in_len);
break;
default:
- OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_PADDING_TYPE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
@@ -156,7 +165,7 @@ static int encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
if (BN_ucmp(f, rsa->n) >= 0) {
/* usually the padding functions would catch this */
- OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
goto err;
}
@@ -175,7 +184,7 @@ static int encrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
/* put in leading 0 bytes if the number is less than the length of the
* modulus */
if (!BN_bn2bin_padded(out, rsa_size, result)) {
- OPENSSL_PUT_ERROR(RSA, encrypt, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -309,13 +318,13 @@ static int sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
int i, ret = 0;
if (max_out < rsa_size) {
- OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
buf = OPENSSL_malloc(rsa_size);
if (buf == NULL) {
- OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -327,7 +336,7 @@ static int sign_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
i = RSA_padding_add_none(buf, rsa_size, in, in_len);
break;
default:
- OPENSSL_PUT_ERROR(RSA, sign_raw, RSA_R_UNKNOWN_PADDING_TYPE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
@@ -359,18 +368,23 @@ static int decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
int ret = 0;
if (max_out < rsa_size) {
- OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
- buf = OPENSSL_malloc(rsa_size);
- if (buf == NULL) {
- OPENSSL_PUT_ERROR(RSA, decrypt, ERR_R_MALLOC_FAILURE);
- goto err;
+ if (padding == RSA_NO_PADDING) {
+ buf = out;
+ } else {
+ /* Allocate a temporary buffer to hold the padded plaintext. */
+ buf = OPENSSL_malloc(rsa_size);
+ if (buf == NULL) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
}
if (in_len != rsa_size) {
- OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
goto err;
}
@@ -388,22 +402,22 @@ static int decrypt(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
NULL, 0, NULL, NULL);
break;
case RSA_NO_PADDING:
- r = RSA_padding_check_none(out, rsa_size, buf, rsa_size);
+ r = rsa_size;
break;
default:
- OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_UNKNOWN_PADDING_TYPE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
if (r < 0) {
- OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_PADDING_CHECK_FAILED);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED);
} else {
*out_len = r;
ret = 1;
}
err:
- if (buf != NULL) {
+ if (padding != RSA_NO_PADDING && buf != NULL) {
OPENSSL_cleanse(buf, rsa_size);
OPENSSL_free(buf);
}
@@ -421,24 +435,24 @@ static int verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
BN_CTX *ctx = NULL;
if (BN_num_bits(rsa->n) > OPENSSL_RSA_MAX_MODULUS_BITS) {
- OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_MODULUS_TOO_LARGE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_MODULUS_TOO_LARGE);
return 0;
}
if (BN_ucmp(rsa->n, rsa->e) <= 0) {
- OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_BAD_E_VALUE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
return 0;
}
if (max_out < rsa_size) {
- OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
/* for large moduli, enforce exponent limit */
if (BN_num_bits(rsa->n) > OPENSSL_RSA_SMALL_MODULUS_BITS &&
BN_num_bits(rsa->e) > OPENSSL_RSA_MAX_PUBEXP_BITS) {
- OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_BAD_E_VALUE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_E_VALUE);
return 0;
}
@@ -450,14 +464,23 @@ static int verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
result = BN_CTX_get(ctx);
- buf = OPENSSL_malloc(rsa_size);
- if (!f || !result || !buf) {
- OPENSSL_PUT_ERROR(RSA, verify_raw, ERR_R_MALLOC_FAILURE);
+ if (padding == RSA_NO_PADDING) {
+ buf = out;
+ } else {
+ /* Allocate a temporary buffer to hold the padded plaintext. */
+ buf = OPENSSL_malloc(rsa_size);
+ if (buf == NULL) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ }
+ if (!f || !result) {
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
if (in_len != rsa_size) {
- OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
goto err;
}
@@ -466,7 +489,7 @@ static int verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
}
if (BN_ucmp(f, rsa->n) >= 0) {
- OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
goto err;
}
@@ -483,7 +506,7 @@ static int verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
}
if (!BN_bn2bin_padded(buf, rsa_size, result)) {
- OPENSSL_PUT_ERROR(RSA, verify_raw, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -492,15 +515,15 @@ static int verify_raw(RSA *rsa, size_t *out_len, uint8_t *out, size_t max_out,
r = RSA_padding_check_PKCS1_type_1(out, rsa_size, buf, rsa_size);
break;
case RSA_NO_PADDING:
- r = RSA_padding_check_none(out, rsa_size, buf, rsa_size);
+ r = rsa_size;
break;
default:
- OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_PADDING_TYPE);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
if (r < 0) {
- OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_PADDING_CHECK_FAILED);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED);
} else {
*out_len = r;
ret = 1;
@@ -511,7 +534,7 @@ err:
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
- if (buf != NULL) {
+ if (padding != RSA_NO_PADDING && buf != NULL) {
OPENSSL_cleanse(buf, rsa_size);
OPENSSL_free(buf);
}
@@ -535,7 +558,7 @@ static int private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
result = BN_CTX_get(ctx);
if (f == NULL || result == NULL) {
- OPENSSL_PUT_ERROR(RSA, private_transform, ERR_R_MALLOC_FAILURE);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_MALLOC_FAILURE);
goto err;
}
@@ -545,14 +568,14 @@ static int private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
if (BN_ucmp(f, rsa->n) >= 0) {
/* Usually the padding functions would catch this. */
- OPENSSL_PUT_ERROR(RSA, private_transform, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
goto err;
}
if (!(rsa->flags & RSA_FLAG_NO_BLINDING)) {
blinding = rsa_blinding_get(rsa, &blinding_index, ctx);
if (blinding == NULL) {
- OPENSSL_PUT_ERROR(RSA, private_transform, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
if (!BN_BLINDING_convert_ex(f, NULL, blinding, ctx)) {
@@ -593,7 +616,7 @@ static int private_transform(RSA *rsa, uint8_t *out, const uint8_t *in,
}
if (!BN_bn2bin_padded(out, len, result)) {
- OPENSSL_PUT_ERROR(RSA, private_transform, ERR_R_INTERNAL_ERROR);
+ OPENSSL_PUT_ERROR(RSA, ERR_R_INTERNAL_ERROR);
goto err;
}
@@ -616,6 +639,11 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
BIGNUM local_dmp1, local_dmq1, local_c, local_r1;
BIGNUM *dmp1, *dmq1, *c, *pr1;
int ret = 0;
+ size_t i, num_additional_primes = 0;
+
+ if (rsa->additional_primes != NULL) {
+ num_additional_primes = sk_RSA_additional_prime_num(rsa->additional_primes);
+ }
BN_CTX_start(ctx);
r1 = BN_CTX_get(ctx);
@@ -724,6 +752,42 @@ static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) {
goto err;
}
+ for (i = 0; i < num_additional_primes; i++) {
+ /* multi-prime RSA. */
+ BIGNUM local_exp, local_prime;
+ BIGNUM *exp = &local_exp, *prime = &local_prime;
+ RSA_additional_prime *ap =
+ sk_RSA_additional_prime_value(rsa->additional_primes, i);
+
+ BN_with_flags(exp, ap->exp, BN_FLG_CONSTTIME);
+ BN_with_flags(prime, ap->prime, BN_FLG_CONSTTIME);
+
+ /* c will already point to a BIGNUM with the correct flags. */
+ if (!BN_mod(r1, c, prime, ctx)) {
+ goto err;
+ }
+
+ if ((rsa->flags & RSA_FLAG_CACHE_PRIVATE) &&
+ !BN_MONT_CTX_set_locked(&ap->method_mod, &rsa->lock, prime, ctx)) {
+ goto err;
+ }
+
+ if (!rsa->meth->bn_mod_exp(m1, r1, exp, prime, ctx, ap->method_mod)) {
+ goto err;
+ }
+
+ BN_set_flags(m1, BN_FLG_CONSTTIME);
+
+ if (!BN_sub(m1, m1, r0) ||
+ !BN_mul(m1, m1, ap->coeff, ctx) ||
+ !BN_mod(m1, m1, prime, ctx) ||
+ (BN_is_negative(m1) && !BN_add(m1, m1, prime)) ||
+ !BN_mul(m1, m1, ap->r, ctx) ||
+ !BN_add(r0, r0, m1)) {
+ goto err;
+ }
+ }
+
if (rsa->e && rsa->n) {
if (!rsa->meth->bn_mod_exp(vrfy, r0, rsa->e, rsa->n, ctx,
rsa->_method_mod_n)) {
@@ -766,12 +830,20 @@ err:
return ret;
}
-static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
+static int keygen_multiprime(RSA *rsa, int bits, int num_primes,
+ BIGNUM *e_value, BN_GENCB *cb) {
BIGNUM *r0 = NULL, *r1 = NULL, *r2 = NULL, *r3 = NULL, *tmp;
BIGNUM local_r0, local_d, local_p;
BIGNUM *pr0, *d, *p;
- int bitsp, bitsq, ok = -1, n = 0;
+ int prime_bits, ok = -1, n = 0, i, j;
BN_CTX *ctx = NULL;
+ STACK_OF(RSA_additional_prime) *additional_primes = NULL;
+
+ if (num_primes < 2) {
+ ok = 0; /* we set our own err */
+ OPENSSL_PUT_ERROR(RSA, RSA_R_MUST_HAVE_AT_LEAST_TWO_PRIMES);
+ goto err;
+ }
ctx = BN_CTX_new();
if (ctx == NULL) {
@@ -782,12 +854,36 @@ static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
r1 = BN_CTX_get(ctx);
r2 = BN_CTX_get(ctx);
r3 = BN_CTX_get(ctx);
- if (r3 == NULL) {
+ if (r0 == NULL || r1 == NULL || r2 == NULL || r3 == NULL) {
goto err;
}
- bitsp = (bits + 1) / 2;
- bitsq = bits - bitsp;
+ if (num_primes > 2) {
+ additional_primes = sk_RSA_additional_prime_new_null();
+ if (additional_primes == NULL) {
+ goto err;
+ }
+ }
+
+ for (i = 2; i < num_primes; i++) {
+ RSA_additional_prime *ap = OPENSSL_malloc(sizeof(RSA_additional_prime));
+ if (ap == NULL) {
+ goto err;
+ }
+ memset(ap, 0, sizeof(RSA_additional_prime));
+ ap->prime = BN_new();
+ ap->exp = BN_new();
+ ap->coeff = BN_new();
+ ap->r = BN_new();
+ if (ap->prime == NULL ||
+ ap->exp == NULL ||
+ ap->coeff == NULL ||
+ ap->r == NULL ||
+ !sk_RSA_additional_prime_push(additional_primes, ap)) {
+ RSA_additional_prime_free(ap);
+ goto err;
+ }
+ }
/* We need the RSA components non-NULL */
if (!rsa->n && ((rsa->n = BN_new()) == NULL)) {
@@ -815,11 +911,14 @@ static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
goto err;
}
- BN_copy(rsa->e, e_value);
+ if (!BN_copy(rsa->e, e_value)) {
+ goto err;
+ }
/* generate p and q */
+ prime_bits = (bits + (num_primes - 1)) / num_primes;
for (;;) {
- if (!BN_generate_prime_ex(rsa->p, bitsp, 0, NULL, NULL, cb) ||
+ if (!BN_generate_prime_ex(rsa->p, prime_bits, 0, NULL, NULL, cb) ||
!BN_sub(r2, rsa->p, BN_value_one()) ||
!BN_gcd(r1, r2, rsa->e, ctx)) {
goto err;
@@ -834,19 +933,20 @@ static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
if (!BN_GENCB_call(cb, 3, 0)) {
goto err;
}
+ prime_bits = ((bits - prime_bits) + (num_primes - 2)) / (num_primes - 1);
for (;;) {
/* When generating ridiculously small keys, we can get stuck
* continually regenerating the same prime values. Check for
* this and bail if it happens 3 times. */
unsigned int degenerate = 0;
do {
- if (!BN_generate_prime_ex(rsa->q, bitsq, 0, NULL, NULL, cb)) {
+ if (!BN_generate_prime_ex(rsa->q, prime_bits, 0, NULL, NULL, cb)) {
goto err;
}
} while ((BN_cmp(rsa->p, rsa->q) == 0) && (++degenerate < 3));
if (degenerate == 3) {
ok = 0; /* we set our own err */
- OPENSSL_PUT_ERROR(RSA, keygen, RSA_R_KEY_SIZE_TOO_SMALL);
+ OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
goto err;
}
if (!BN_sub(r2, rsa->q, BN_value_one()) ||
@@ -860,20 +960,91 @@ static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
goto err;
}
}
- if (!BN_GENCB_call(cb, 3, 1)) {
+
+ if (!BN_GENCB_call(cb, 3, 1) ||
+ !BN_mul(rsa->n, rsa->p, rsa->q, ctx)) {
goto err;
}
+
+ for (i = 2; i < num_primes; i++) {
+ RSA_additional_prime *ap =
+ sk_RSA_additional_prime_value(additional_primes, i - 2);
+ prime_bits = ((bits - BN_num_bits(rsa->n)) + (num_primes - (i + 1))) /
+ (num_primes - i);
+
+ for (;;) {
+ if (!BN_generate_prime_ex(ap->prime, prime_bits, 0, NULL, NULL, cb)) {
+ goto err;
+ }
+ if (BN_cmp(rsa->p, ap->prime) == 0 ||
+ BN_cmp(rsa->q, ap->prime) == 0) {
+ continue;
+ }
+
+ for (j = 0; j < i - 2; j++) {
+ if (BN_cmp(sk_RSA_additional_prime_value(additional_primes, j)->prime,
+ ap->prime) == 0) {
+ break;
+ }
+ }
+ if (j != i - 2) {
+ continue;
+ }
+
+ if (!BN_sub(r2, ap->prime, BN_value_one()) ||
+ !BN_gcd(r1, r2, rsa->e, ctx)) {
+ goto err;
+ }
+
+ if (!BN_is_one(r1)) {
+ continue;
+ }
+ if (i != num_primes - 1) {
+ break;
+ }
+
+ /* For the last prime we'll check that it makes n large enough. In the
+ * two prime case this isn't a problem because we generate primes with
+ * the top two bits set and so the product is always of the expected
+ * size. In the multi prime case, this doesn't follow. */
+ if (!BN_mul(r1, rsa->n, ap->prime, ctx)) {
+ goto err;
+ }
+ if (BN_num_bits(r1) == bits) {
+ break;
+ }
+
+ if (!BN_GENCB_call(cb, 2, n++)) {
+ goto err;
+ }
+ }
+
+ /* ap->r is is the product of all the primes prior to the current one
+ * (including p and q). */
+ if (!BN_copy(ap->r, rsa->n)) {
+ goto err;
+ }
+ if (i == num_primes - 1) {
+ /* In the case of the last prime, we calculated n as |r1| in the loop
+ * above. */
+ if (!BN_copy(rsa->n, r1)) {
+ goto err;
+ }
+ } else if (!BN_mul(rsa->n, rsa->n, ap->prime, ctx)) {
+ goto err;
+ }
+
+ if (!BN_GENCB_call(cb, 3, 1)) {
+ goto err;
+ }
+ }
+
if (BN_cmp(rsa->p, rsa->q) < 0) {
tmp = rsa->p;
rsa->p = rsa->q;
rsa->q = tmp;
}
- /* calculate n */
- if (!BN_mul(rsa->n, rsa->p, rsa->q, ctx)) {
- goto err;
- }
-
/* calculate d */
if (!BN_sub(r1, rsa->p, BN_value_one())) {
goto err; /* p-1 */
@@ -884,6 +1055,14 @@ static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
if (!BN_mul(r0, r1, r2, ctx)) {
goto err; /* (p-1)(q-1) */
}
+ for (i = 2; i < num_primes; i++) {
+ RSA_additional_prime *ap =
+ sk_RSA_additional_prime_value(additional_primes, i - 2);
+ if (!BN_sub(r3, ap->prime, BN_value_one()) ||
+ !BN_mul(r0, r0, r3, ctx)) {
+ goto err;
+ }
+ }
pr0 = &local_r0;
BN_with_flags(pr0, r0, BN_FLG_CONSTTIME);
if (!BN_mod_inverse(rsa->d, rsa->e, pr0, ctx)) {
@@ -912,21 +1091,38 @@ static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
goto err;
}
+ for (i = 2; i < num_primes; i++) {
+ RSA_additional_prime *ap =
+ sk_RSA_additional_prime_value(additional_primes, i - 2);
+ if (!BN_sub(ap->exp, ap->prime, BN_value_one()) ||
+ !BN_mod(ap->exp, rsa->d, ap->exp, ctx) ||
+ !BN_mod_inverse(ap->coeff, ap->r, ap->prime, ctx)) {
+ goto err;
+ }
+ }
+
ok = 1;
+ rsa->additional_primes = additional_primes;
+ additional_primes = NULL;
err:
if (ok == -1) {
- OPENSSL_PUT_ERROR(RSA, keygen, ERR_LIB_BN);
+ OPENSSL_PUT_ERROR(RSA, ERR_LIB_BN);
ok = 0;
}
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
-
+ sk_RSA_additional_prime_pop_free(additional_primes,
+ RSA_additional_prime_free);
return ok;
}
+static int keygen(RSA *rsa, int bits, BIGNUM *e_value, BN_GENCB *cb) {
+ return keygen_multiprime(rsa, bits, 2 /* num primes */, e_value, cb);
+}
+
const struct rsa_meth_st RSA_default_method = {
{
0 /* references */,
@@ -955,4 +1151,7 @@ const struct rsa_meth_st RSA_default_method = {
RSA_FLAG_CACHE_PUBLIC | RSA_FLAG_CACHE_PRIVATE,
keygen,
+ keygen_multiprime,
+
+ NULL /* supports_digest */,
};
diff --git a/src/crypto/rsa/rsa_test.c b/src/crypto/rsa/rsa_test.c
deleted file mode 100644
index 318cf3f..0000000
--- a/src/crypto/rsa/rsa_test.c
+++ /dev/null
@@ -1,511 +0,0 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
- *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to. The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code. The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * "This product includes cryptographic software written by
- * Eric Young (eay@cryptsoft.com)"
- * The word 'cryptographic' can be left out if the rouines from the library
- * being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- * the apps directory (application code) you must include an acknowledgement:
- * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed. i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.] */
-
-#include <openssl/rsa.h>
-
-#include <stdlib.h>
-#include <string.h>
-
-#include <openssl/bn.h>
-#include <openssl/crypto.h>
-#include <openssl/err.h>
-#include <openssl/obj.h>
-
-
-#define SetKey \
- key->n = BN_bin2bn(n, sizeof(n) - 1, key->n); \
- key->e = BN_bin2bn(e, sizeof(e) - 1, key->e); \
- key->d = BN_bin2bn(d, sizeof(d) - 1, key->d); \
- key->p = BN_bin2bn(p, sizeof(p) - 1, key->p); \
- key->q = BN_bin2bn(q, sizeof(q) - 1, key->q); \
- key->dmp1 = BN_bin2bn(dmp1, sizeof(dmp1) - 1, key->dmp1); \
- key->dmq1 = BN_bin2bn(dmq1, sizeof(dmq1) - 1, key->dmq1); \
- key->iqmp = BN_bin2bn(iqmp, sizeof(iqmp) - 1, key->iqmp); \
- memcpy(c, ctext_ex, sizeof(ctext_ex) - 1); \
- return (sizeof(ctext_ex) - 1);
-
-static int key1(RSA *key, unsigned char *c) {
- static unsigned char n[] =
- "\x00\xAA\x36\xAB\xCE\x88\xAC\xFD\xFF\x55\x52\x3C\x7F\xC4\x52\x3F"
- "\x90\xEF\xA0\x0D\xF3\x77\x4A\x25\x9F\x2E\x62\xB4\xC5\xD9\x9C\xB5"
- "\xAD\xB3\x00\xA0\x28\x5E\x53\x01\x93\x0E\x0C\x70\xFB\x68\x76\x93"
- "\x9C\xE6\x16\xCE\x62\x4A\x11\xE0\x08\x6D\x34\x1E\xBC\xAC\xA0\xA1"
- "\xF5";
-
- static unsigned char e[] = "\x11";
-
- static unsigned char d[] =
- "\x0A\x03\x37\x48\x62\x64\x87\x69\x5F\x5F\x30\xBC\x38\xB9\x8B\x44"
- "\xC2\xCD\x2D\xFF\x43\x40\x98\xCD\x20\xD8\xA1\x38\xD0\x90\xBF\x64"
- "\x79\x7C\x3F\xA7\xA2\xCD\xCB\x3C\xD1\xE0\xBD\xBA\x26\x54\xB4\xF9"
- "\xDF\x8E\x8A\xE5\x9D\x73\x3D\x9F\x33\xB3\x01\x62\x4A\xFD\x1D\x51";
-
- static unsigned char p[] =
- "\x00\xD8\x40\xB4\x16\x66\xB4\x2E\x92\xEA\x0D\xA3\xB4\x32\x04\xB5"
- "\xCF\xCE\x33\x52\x52\x4D\x04\x16\xA5\xA4\x41\xE7\x00\xAF\x46\x12"
- "\x0D";
-
- static unsigned char q[] =
- "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9"
- "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5A\x0F\x20\x35\x02\x8B\x9D"
- "\x89";
-
- static unsigned char dmp1[] =
- "\x59\x0B\x95\x72\xA2\xC2\xA9\xC4\x06\x05\x9D\xC2\xAB\x2F\x1D\xAF"
- "\xEB\x7E\x8B\x4F\x10\xA7\x54\x9E\x8E\xED\xF5\xB4\xFC\xE0\x9E\x05";
-
- static unsigned char dmq1[] =
- "\x00\x8E\x3C\x05\x21\xFE\x15\xE0\xEA\x06\xA3\x6F\xF0\xF1\x0C\x99"
- "\x52\xC3\x5B\x7A\x75\x14\xFD\x32\x38\xB8\x0A\xAD\x52\x98\x62\x8D"
- "\x51";
-
- static unsigned char iqmp[] =
- "\x36\x3F\xF7\x18\x9D\xA8\xE9\x0B\x1D\x34\x1F\x71\xD0\x9B\x76\xA8"
- "\xA9\x43\xE1\x1D\x10\xB2\x4D\x24\x9F\x2D\xEA\xFE\xF8\x0C\x18\x26";
-
- static unsigned char ctext_ex[] =
- "\x1b\x8f\x05\xf9\xca\x1a\x79\x52\x6e\x53\xf3\xcc\x51\x4f\xdb\x89"
- "\x2b\xfb\x91\x93\x23\x1e\x78\xb9\x92\xe6\x8d\x50\xa4\x80\xcb\x52"
- "\x33\x89\x5c\x74\x95\x8d\x5d\x02\xab\x8c\x0f\xd0\x40\xeb\x58\x44"
- "\xb0\x05\xc3\x9e\xd8\x27\x4a\x9d\xbf\xa8\x06\x71\x40\x94\x39\xd2";
-
- SetKey;
-}
-
-static int key2(RSA *key, unsigned char *c) {
- static unsigned char n[] =
- "\x00\xA3\x07\x9A\x90\xDF\x0D\xFD\x72\xAC\x09\x0C\xCC\x2A\x78\xB8"
- "\x74\x13\x13\x3E\x40\x75\x9C\x98\xFA\xF8\x20\x4F\x35\x8A\x0B\x26"
- "\x3C\x67\x70\xE7\x83\xA9\x3B\x69\x71\xB7\x37\x79\xD2\x71\x7B\xE8"
- "\x34\x77\xCF";
-
- static unsigned char e[] = "\x3";
-
- static unsigned char d[] =
- "\x6C\xAF\xBC\x60\x94\xB3\xFE\x4C\x72\xB0\xB3\x32\xC6\xFB\x25\xA2"
- "\xB7\x62\x29\x80\x4E\x68\x65\xFC\xA4\x5A\x74\xDF\x0F\x8F\xB8\x41"
- "\x3B\x52\xC0\xD0\xE5\x3D\x9B\x59\x0F\xF1\x9B\xE7\x9F\x49\xDD\x21"
- "\xE5\xEB";
-
- static unsigned char p[] =
- "\x00\xCF\x20\x35\x02\x8B\x9D\x86\x98\x40\xB4\x16\x66\xB4\x2E\x92"
- "\xEA\x0D\xA3\xB4\x32\x04\xB5\xCF\xCE\x91";
-
- static unsigned char q[] =
- "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9"
- "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5F";
-
- static unsigned char dmp1[] =
- "\x00\x8A\x15\x78\xAC\x5D\x13\xAF\x10\x2B\x22\xB9\x99\xCD\x74\x61"
- "\xF1\x5E\x6D\x22\xCC\x03\x23\xDF\xDF\x0B";
-
- static unsigned char dmq1[] =
- "\x00\x86\x55\x21\x4A\xC5\x4D\x8D\x4E\xCD\x61\x77\xF1\xC7\x36\x90"
- "\xCE\x2A\x48\x2C\x8B\x05\x99\xCB\xE0\x3F";
-
- static unsigned char iqmp[] =
- "\x00\x83\xEF\xEF\xB8\xA9\xA4\x0D\x1D\xB6\xED\x98\xAD\x84\xED\x13"
- "\x35\xDC\xC1\x08\xF3\x22\xD0\x57\xCF\x8D";
-
- static unsigned char ctext_ex[] =
- "\x14\xbd\xdd\x28\xc9\x83\x35\x19\x23\x80\xe8\xe5\x49\xb1\x58\x2a"
- "\x8b\x40\xb4\x48\x6d\x03\xa6\xa5\x31\x1f\x1f\xd5\xf0\xa1\x80\xe4"
- "\x17\x53\x03\x29\xa9\x34\x90\x74\xb1\x52\x13\x54\x29\x08\x24\x52"
- "\x62\x51";
-
- SetKey;
-}
-
-static int key3(RSA *key, unsigned char *c) {
- static unsigned char n[] =
- "\x00\xBB\xF8\x2F\x09\x06\x82\xCE\x9C\x23\x38\xAC\x2B\x9D\xA8\x71"
- "\xF7\x36\x8D\x07\xEE\xD4\x10\x43\xA4\x40\xD6\xB6\xF0\x74\x54\xF5"
- "\x1F\xB8\xDF\xBA\xAF\x03\x5C\x02\xAB\x61\xEA\x48\xCE\xEB\x6F\xCD"
- "\x48\x76\xED\x52\x0D\x60\xE1\xEC\x46\x19\x71\x9D\x8A\x5B\x8B\x80"
- "\x7F\xAF\xB8\xE0\xA3\xDF\xC7\x37\x72\x3E\xE6\xB4\xB7\xD9\x3A\x25"
- "\x84\xEE\x6A\x64\x9D\x06\x09\x53\x74\x88\x34\xB2\x45\x45\x98\x39"
- "\x4E\xE0\xAA\xB1\x2D\x7B\x61\xA5\x1F\x52\x7A\x9A\x41\xF6\xC1\x68"
- "\x7F\xE2\x53\x72\x98\xCA\x2A\x8F\x59\x46\xF8\xE5\xFD\x09\x1D\xBD"
- "\xCB";
-
- static unsigned char e[] = "\x11";
-
- static unsigned char d[] =
- "\x00\xA5\xDA\xFC\x53\x41\xFA\xF2\x89\xC4\xB9\x88\xDB\x30\xC1\xCD"
- "\xF8\x3F\x31\x25\x1E\x06\x68\xB4\x27\x84\x81\x38\x01\x57\x96\x41"
- "\xB2\x94\x10\xB3\xC7\x99\x8D\x6B\xC4\x65\x74\x5E\x5C\x39\x26\x69"
- "\xD6\x87\x0D\xA2\xC0\x82\xA9\x39\xE3\x7F\xDC\xB8\x2E\xC9\x3E\xDA"
- "\xC9\x7F\xF3\xAD\x59\x50\xAC\xCF\xBC\x11\x1C\x76\xF1\xA9\x52\x94"
- "\x44\xE5\x6A\xAF\x68\xC5\x6C\x09\x2C\xD3\x8D\xC3\xBE\xF5\xD2\x0A"
- "\x93\x99\x26\xED\x4F\x74\xA1\x3E\xDD\xFB\xE1\xA1\xCE\xCC\x48\x94"
- "\xAF\x94\x28\xC2\xB7\xB8\x88\x3F\xE4\x46\x3A\x4B\xC8\x5B\x1C\xB3"
- "\xC1";
-
- static unsigned char p[] =
- "\x00\xEE\xCF\xAE\x81\xB1\xB9\xB3\xC9\x08\x81\x0B\x10\xA1\xB5\x60"
- "\x01\x99\xEB\x9F\x44\xAE\xF4\xFD\xA4\x93\xB8\x1A\x9E\x3D\x84\xF6"
- "\x32\x12\x4E\xF0\x23\x6E\x5D\x1E\x3B\x7E\x28\xFA\xE7\xAA\x04\x0A"
- "\x2D\x5B\x25\x21\x76\x45\x9D\x1F\x39\x75\x41\xBA\x2A\x58\xFB\x65"
- "\x99";
-
- static unsigned char q[] =
- "\x00\xC9\x7F\xB1\xF0\x27\xF4\x53\xF6\x34\x12\x33\xEA\xAA\xD1\xD9"
- "\x35\x3F\x6C\x42\xD0\x88\x66\xB1\xD0\x5A\x0F\x20\x35\x02\x8B\x9D"
- "\x86\x98\x40\xB4\x16\x66\xB4\x2E\x92\xEA\x0D\xA3\xB4\x32\x04\xB5"
- "\xCF\xCE\x33\x52\x52\x4D\x04\x16\xA5\xA4\x41\xE7\x00\xAF\x46\x15"
- "\x03";
-
- static unsigned char dmp1[] =
- "\x54\x49\x4C\xA6\x3E\xBA\x03\x37\xE4\xE2\x40\x23\xFC\xD6\x9A\x5A"
- "\xEB\x07\xDD\xDC\x01\x83\xA4\xD0\xAC\x9B\x54\xB0\x51\xF2\xB1\x3E"
- "\xD9\x49\x09\x75\xEA\xB7\x74\x14\xFF\x59\xC1\xF7\x69\x2E\x9A\x2E"
- "\x20\x2B\x38\xFC\x91\x0A\x47\x41\x74\xAD\xC9\x3C\x1F\x67\xC9\x81";
-
- static unsigned char dmq1[] =
- "\x47\x1E\x02\x90\xFF\x0A\xF0\x75\x03\x51\xB7\xF8\x78\x86\x4C\xA9"
- "\x61\xAD\xBD\x3A\x8A\x7E\x99\x1C\x5C\x05\x56\xA9\x4C\x31\x46\xA7"
- "\xF9\x80\x3F\x8F\x6F\x8A\xE3\x42\xE9\x31\xFD\x8A\xE4\x7A\x22\x0D"
- "\x1B\x99\xA4\x95\x84\x98\x07\xFE\x39\xF9\x24\x5A\x98\x36\xDA\x3D";
-
- static unsigned char iqmp[] =
- "\x00\xB0\x6C\x4F\xDA\xBB\x63\x01\x19\x8D\x26\x5B\xDB\xAE\x94\x23"
- "\xB3\x80\xF2\x71\xF7\x34\x53\x88\x50\x93\x07\x7F\xCD\x39\xE2\x11"
- "\x9F\xC9\x86\x32\x15\x4F\x58\x83\xB1\x67\xA9\x67\xBF\x40\x2B\x4E"
- "\x9E\x2E\x0F\x96\x56\xE6\x98\xEA\x36\x66\xED\xFB\x25\x79\x80\x39"
- "\xF7";
-
- static unsigned char ctext_ex[] =
- "\xb8\x24\x6b\x56\xa6\xed\x58\x81\xae\xb5\x85\xd9\xa2\x5b\x2a\xd7"
- "\x90\xc4\x17\xe0\x80\x68\x1b\xf1\xac\x2b\xc3\xde\xb6\x9d\x8b\xce"
- "\xf0\xc4\x36\x6f\xec\x40\x0a\xf0\x52\xa7\x2e\x9b\x0e\xff\xb5\xb3"
- "\xf2\xf1\x92\xdb\xea\xca\x03\xc1\x27\x40\x05\x71\x13\xbf\x1f\x06"
- "\x69\xac\x22\xe9\xf3\xa7\x85\x2e\x3c\x15\xd9\x13\xca\xb0\xb8\x86"
- "\x3a\x95\xc9\x92\x94\xce\x86\x74\x21\x49\x54\x61\x03\x46\xf4\xd4"
- "\x74\xb2\x6f\x7c\x48\xb4\x2e\xe6\x8e\x1f\x57\x2a\x1f\xc4\x02\x6a"
- "\xc4\x56\xb4\xf5\x9f\x7b\x62\x1e\xa1\xb9\xd8\x8f\x64\x20\x2f\xb1";
-
- SetKey;
-}
-
-static int test_bad_key(void) {
- RSA *key = RSA_new();
- BIGNUM e;
-
- BN_init(&e);
- BN_set_word(&e, RSA_F4);
-
- if (!RSA_generate_key_ex(key, 512, &e, NULL)) {
- fprintf(stderr, "RSA_generate_key_ex failed.\n");
- ERR_print_errors_fp(stderr);
- return 0;
- }
-
- if (!BN_add(key->p, key->p, BN_value_one())) {
- fprintf(stderr, "BN error.\n");
- ERR_print_errors_fp(stderr);
- return 0;
- }
-
- if (RSA_check_key(key)) {
- fprintf(stderr, "RSA_check_key passed with invalid key!\n");
- return 0;
- }
-
- ERR_clear_error();
- BN_free(&e);
- RSA_free(key);
- return 1;
-}
-
-static int test_only_d_given(void) {
- RSA *key = RSA_new();
- uint8_t buf[64];
- unsigned buf_len = sizeof(buf);
- const uint8_t kDummyHash[16] = {0};
- int ret = 0;
-
- if (!BN_hex2bn(&key->n,
- "00e77bbf3889d4ef36a9a25d4d69f3f632eb4362214c74517da6d6aeaa9bd"
- "09ac42b26621cd88f3a6eb013772fc3bf9f83914b6467231c630202c35b3e"
- "5808c659") ||
- !BN_hex2bn(&key->e, "010001") ||
- !BN_hex2bn(&key->d,
- "0365db9eb6d73b53b015c40cd8db4de7dd7035c68b5ac1bf786d7a4ee2cea"
- "316eaeca21a73ac365e58713195f2ae9849348525ca855386b6d028e437a9"
- "495a01") ||
- RSA_size(key) > sizeof(buf)) {
- goto err;
- }
-
- if (!RSA_check_key(key)) {
- fprintf(stderr, "RSA_check_key failed with only d given.\n");
- ERR_print_errors_fp(stderr);
- goto err;
- }
-
- if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
- key)) {
- fprintf(stderr, "RSA_sign failed with only d given.\n");
- ERR_print_errors_fp(stderr);
- goto err;
- }
-
- if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
- key)) {
- fprintf(stderr, "RSA_verify failed with only d given.\n");
- ERR_print_errors_fp(stderr);
- goto err;
- }
-
- ret = 1;
-
-err:
- RSA_free(key);
- return ret;
-}
-
-static int test_recover_crt_params(void) {
- RSA *key1, *key2;
- BIGNUM *e = BN_new();
- uint8_t buf[128];
- unsigned buf_len = sizeof(buf);
- const uint8_t kDummyHash[16] = {0};
- unsigned i;
-
- BN_set_word(e, RSA_F4);
-
- ERR_clear_error();
-
- for (i = 0; i < 1; i++) {
- key1 = RSA_new();
- if (!RSA_generate_key_ex(key1, 512, e, NULL)) {
- fprintf(stderr, "RSA_generate_key_ex failed.\n");
- ERR_print_errors_fp(stderr);
- return 0;
- }
-
- if (!RSA_check_key(key1)) {
- fprintf(stderr, "RSA_check_key failed with original key.\n");
- ERR_print_errors_fp(stderr);
- return 0;
- }
-
- key2 = RSA_new();
- key2->n = BN_dup(key1->n);
- key2->e = BN_dup(key1->e);
- key2->d = BN_dup(key1->d);
- RSA_free(key1);
-
- if (!RSA_recover_crt_params(key2)) {
- fprintf(stderr, "RSA_recover_crt_params failed.\n");
- ERR_print_errors_fp(stderr);
- return 0;
- }
-
- if (RSA_size(key2) > buf_len) {
- return 0;
- }
-
- if (!RSA_check_key(key2)) {
- fprintf(stderr, "RSA_check_key failed with recovered key.\n");
- ERR_print_errors_fp(stderr);
- return 0;
- }
-
- if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
- key2)) {
- fprintf(stderr, "RSA_sign failed with recovered key.\n");
- ERR_print_errors_fp(stderr);
- return 0;
- }
-
- if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
- key2)) {
- fprintf(stderr, "RSA_verify failed with recovered key.\n");
- ERR_print_errors_fp(stderr);
- return 0;
- }
-
- RSA_free(key2);
- }
-
- BN_free(e);
- return 1;
-}
-
-int main(int argc, char *argv[]) {
- int err = 0;
- int v;
- RSA *key;
- unsigned char ptext[256];
- unsigned char ctext[256];
- static unsigned char ptext_ex[] = "\x54\x85\x9b\x34\x2c\x49\xea\x2a";
- unsigned char ctext_ex[256];
- int plen;
- int clen = 0;
- int num;
- int n;
-
- CRYPTO_library_init();
-
- plen = sizeof(ptext_ex) - 1;
-
- for (v = 0; v < 3; v++) {
- key = RSA_new();
- switch (v) {
- case 0:
- clen = key1(key, ctext_ex);
- break;
- case 1:
- clen = key2(key, ctext_ex);
- break;
- case 2:
- clen = key3(key, ctext_ex);
- break;
- default:
- abort();
- }
-
- if (!RSA_check_key(key)) {
- printf("%d: RSA_check_key failed\n", v);
- err = 1;
- goto oaep;
- }
-
- num = RSA_public_encrypt(plen, ptext_ex, ctext, key, RSA_PKCS1_PADDING);
- if (num != clen) {
- printf("PKCS#1 v1.5 encryption failed!\n");
- err = 1;
- goto oaep;
- }
-
- num = RSA_private_decrypt(num, ctext, ptext, key, RSA_PKCS1_PADDING);
- if (num != plen || memcmp(ptext, ptext_ex, num) != 0) {
- printf("PKCS#1 v1.5 decryption failed!\n");
- err = 1;
- } else {
- printf("PKCS #1 v1.5 encryption/decryption ok\n");
- }
-
- oaep:
- ERR_clear_error();
- num =
- RSA_public_encrypt(plen, ptext_ex, ctext, key, RSA_PKCS1_OAEP_PADDING);
- if (num == -1) {
- printf("No OAEP support\n");
- goto next;
- }
- if (num != clen) {
- printf("OAEP encryption failed!\n");
- err = 1;
- goto next;
- }
-
- num = RSA_private_decrypt(num, ctext, ptext, key, RSA_PKCS1_OAEP_PADDING);
- if (num != plen || memcmp(ptext, ptext_ex, num) != 0) {
- printf("OAEP decryption (encrypted data) failed!\n");
- err = 1;
- } else if (memcmp(ctext, ctext_ex, num) == 0) {
- printf("OAEP test vector %d passed!\n", v);
- }
-
- /* Different ciphertexts (rsa_oaep.c without -DPKCS_TESTVECT).
- Try decrypting ctext_ex */
-
- num =
- RSA_private_decrypt(clen, ctext_ex, ptext, key, RSA_PKCS1_OAEP_PADDING);
-
- if (num != plen || memcmp(ptext, ptext_ex, num) != 0) {
- printf("OAEP decryption (test vector data) failed!\n");
- err = 1;
- } else {
- printf("OAEP encryption/decryption ok\n");
- }
-
- /* Try decrypting corrupted ciphertexts */
- for (n = 0; n < clen; ++n) {
- int b;
- unsigned char saved = ctext[n];
- for (b = 0; b < 256; ++b) {
- if (b == saved) {
- continue;
- }
- ctext[n] = b;
- num =
- RSA_private_decrypt(num, ctext, ptext, key, RSA_PKCS1_OAEP_PADDING);
- if (num > 0) {
- printf("Corrupt data decrypted!\n");
- err = 1;
- }
- }
- }
-
- next:
- RSA_free(key);
- }
-
- if (err != 0 ||
- !test_only_d_given() ||
- !test_recover_crt_params() ||
- !test_bad_key()) {
- err = 1;
- }
-
- if (err == 0) {
- printf("PASS\n");
- }
- return err;
-}
diff --git a/src/crypto/rsa/rsa_test.cc b/src/crypto/rsa/rsa_test.cc
new file mode 100644
index 0000000..d52b78b
--- /dev/null
+++ b/src/crypto/rsa/rsa_test.cc
@@ -0,0 +1,869 @@
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.] */
+
+#include <openssl/rsa.h>
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/bn.h>
+#include <openssl/bytestring.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+#include <openssl/obj.h>
+
+#include "../test/scoped_types.h"
+
+
+// kPlaintext is a sample plaintext.
+static const uint8_t kPlaintext[] = "\x54\x85\x9b\x34\x2c\x49\xea\x2a";
+static const size_t kPlaintextLen = sizeof(kPlaintext) - 1;
+
+// kKey1 is a DER-encoded RSAPrivateKey.
+static const uint8_t kKey1[] =
+ "\x30\x82\x01\x38\x02\x01\x00\x02\x41\x00\xaa\x36\xab\xce\x88\xac\xfd\xff"
+ "\x55\x52\x3c\x7f\xc4\x52\x3f\x90\xef\xa0\x0d\xf3\x77\x4a\x25\x9f\x2e\x62"
+ "\xb4\xc5\xd9\x9c\xb5\xad\xb3\x00\xa0\x28\x5e\x53\x01\x93\x0e\x0c\x70\xfb"
+ "\x68\x76\x93\x9c\xe6\x16\xce\x62\x4a\x11\xe0\x08\x6d\x34\x1e\xbc\xac\xa0"
+ "\xa1\xf5\x02\x01\x11\x02\x40\x0a\x03\x37\x48\x62\x64\x87\x69\x5f\x5f\x30"
+ "\xbc\x38\xb9\x8b\x44\xc2\xcd\x2d\xff\x43\x40\x98\xcd\x20\xd8\xa1\x38\xd0"
+ "\x90\xbf\x64\x79\x7c\x3f\xa7\xa2\xcd\xcb\x3c\xd1\xe0\xbd\xba\x26\x54\xb4"
+ "\xf9\xdf\x8e\x8a\xe5\x9d\x73\x3d\x9f\x33\xb3\x01\x62\x4a\xfd\x1d\x51\x02"
+ "\x21\x00\xd8\x40\xb4\x16\x66\xb4\x2e\x92\xea\x0d\xa3\xb4\x32\x04\xb5\xcf"
+ "\xce\x33\x52\x52\x4d\x04\x16\xa5\xa4\x41\xe7\x00\xaf\x46\x12\x0d\x02\x21"
+ "\x00\xc9\x7f\xb1\xf0\x27\xf4\x53\xf6\x34\x12\x33\xea\xaa\xd1\xd9\x35\x3f"
+ "\x6c\x42\xd0\x88\x66\xb1\xd0\x5a\x0f\x20\x35\x02\x8b\x9d\x89\x02\x20\x59"
+ "\x0b\x95\x72\xa2\xc2\xa9\xc4\x06\x05\x9d\xc2\xab\x2f\x1d\xaf\xeb\x7e\x8b"
+ "\x4f\x10\xa7\x54\x9e\x8e\xed\xf5\xb4\xfc\xe0\x9e\x05\x02\x21\x00\x8e\x3c"
+ "\x05\x21\xfe\x15\xe0\xea\x06\xa3\x6f\xf0\xf1\x0c\x99\x52\xc3\x5b\x7a\x75"
+ "\x14\xfd\x32\x38\xb8\x0a\xad\x52\x98\x62\x8d\x51\x02\x20\x36\x3f\xf7\x18"
+ "\x9d\xa8\xe9\x0b\x1d\x34\x1f\x71\xd0\x9b\x76\xa8\xa9\x43\xe1\x1d\x10\xb2"
+ "\x4d\x24\x9f\x2d\xea\xfe\xf8\x0c\x18\x26";
+
+// kOAEPCiphertext1 is a sample encryption of |kPlaintext| with |kKey1| using
+// RSA OAEP.
+static const uint8_t kOAEPCiphertext1[] =
+ "\x1b\x8f\x05\xf9\xca\x1a\x79\x52\x6e\x53\xf3\xcc\x51\x4f\xdb\x89\x2b\xfb"
+ "\x91\x93\x23\x1e\x78\xb9\x92\xe6\x8d\x50\xa4\x80\xcb\x52\x33\x89\x5c\x74"
+ "\x95\x8d\x5d\x02\xab\x8c\x0f\xd0\x40\xeb\x58\x44\xb0\x05\xc3\x9e\xd8\x27"
+ "\x4a\x9d\xbf\xa8\x06\x71\x40\x94\x39\xd2";
+
+// kKey2 is a DER-encoded RSAPrivateKey.
+static const uint8_t kKey2[] =
+ "\x30\x81\xfb\x02\x01\x00\x02\x33\x00\xa3\x07\x9a\x90\xdf\x0d\xfd\x72\xac"
+ "\x09\x0c\xcc\x2a\x78\xb8\x74\x13\x13\x3e\x40\x75\x9c\x98\xfa\xf8\x20\x4f"
+ "\x35\x8a\x0b\x26\x3c\x67\x70\xe7\x83\xa9\x3b\x69\x71\xb7\x37\x79\xd2\x71"
+ "\x7b\xe8\x34\x77\xcf\x02\x01\x03\x02\x32\x6c\xaf\xbc\x60\x94\xb3\xfe\x4c"
+ "\x72\xb0\xb3\x32\xc6\xfb\x25\xa2\xb7\x62\x29\x80\x4e\x68\x65\xfc\xa4\x5a"
+ "\x74\xdf\x0f\x8f\xb8\x41\x3b\x52\xc0\xd0\xe5\x3d\x9b\x59\x0f\xf1\x9b\xe7"
+ "\x9f\x49\xdd\x21\xe5\xeb\x02\x1a\x00\xcf\x20\x35\x02\x8b\x9d\x86\x98\x40"
+ "\xb4\x16\x66\xb4\x2e\x92\xea\x0d\xa3\xb4\x32\x04\xb5\xcf\xce\x91\x02\x1a"
+ "\x00\xc9\x7f\xb1\xf0\x27\xf4\x53\xf6\x34\x12\x33\xea\xaa\xd1\xd9\x35\x3f"
+ "\x6c\x42\xd0\x88\x66\xb1\xd0\x5f\x02\x1a\x00\x8a\x15\x78\xac\x5d\x13\xaf"
+ "\x10\x2b\x22\xb9\x99\xcd\x74\x61\xf1\x5e\x6d\x22\xcc\x03\x23\xdf\xdf\x0b"
+ "\x02\x1a\x00\x86\x55\x21\x4a\xc5\x4d\x8d\x4e\xcd\x61\x77\xf1\xc7\x36\x90"
+ "\xce\x2a\x48\x2c\x8b\x05\x99\xcb\xe0\x3f\x02\x1a\x00\x83\xef\xef\xb8\xa9"
+ "\xa4\x0d\x1d\xb6\xed\x98\xad\x84\xed\x13\x35\xdc\xc1\x08\xf3\x22\xd0\x57"
+ "\xcf\x8d";
+
+// kOAEPCiphertext2 is a sample encryption of |kPlaintext| with |kKey2| using
+// RSA OAEP.
+static const uint8_t kOAEPCiphertext2[] =
+ "\x14\xbd\xdd\x28\xc9\x83\x35\x19\x23\x80\xe8\xe5\x49\xb1\x58\x2a\x8b\x40"
+ "\xb4\x48\x6d\x03\xa6\xa5\x31\x1f\x1f\xd5\xf0\xa1\x80\xe4\x17\x53\x03\x29"
+ "\xa9\x34\x90\x74\xb1\x52\x13\x54\x29\x08\x24\x52\x62\x51";
+
+// kKey3 is a DER-encoded RSAPrivateKey.
+static const uint8_t kKey3[] =
+ "\x30\x82\x02\x5b\x02\x01\x00\x02\x81\x81\x00\xbb\xf8\x2f\x09\x06\x82\xce"
+ "\x9c\x23\x38\xac\x2b\x9d\xa8\x71\xf7\x36\x8d\x07\xee\xd4\x10\x43\xa4\x40"
+ "\xd6\xb6\xf0\x74\x54\xf5\x1f\xb8\xdf\xba\xaf\x03\x5c\x02\xab\x61\xea\x48"
+ "\xce\xeb\x6f\xcd\x48\x76\xed\x52\x0d\x60\xe1\xec\x46\x19\x71\x9d\x8a\x5b"
+ "\x8b\x80\x7f\xaf\xb8\xe0\xa3\xdf\xc7\x37\x72\x3e\xe6\xb4\xb7\xd9\x3a\x25"
+ "\x84\xee\x6a\x64\x9d\x06\x09\x53\x74\x88\x34\xb2\x45\x45\x98\x39\x4e\xe0"
+ "\xaa\xb1\x2d\x7b\x61\xa5\x1f\x52\x7a\x9a\x41\xf6\xc1\x68\x7f\xe2\x53\x72"
+ "\x98\xca\x2a\x8f\x59\x46\xf8\xe5\xfd\x09\x1d\xbd\xcb\x02\x01\x11\x02\x81"
+ "\x81\x00\xa5\xda\xfc\x53\x41\xfa\xf2\x89\xc4\xb9\x88\xdb\x30\xc1\xcd\xf8"
+ "\x3f\x31\x25\x1e\x06\x68\xb4\x27\x84\x81\x38\x01\x57\x96\x41\xb2\x94\x10"
+ "\xb3\xc7\x99\x8d\x6b\xc4\x65\x74\x5e\x5c\x39\x26\x69\xd6\x87\x0d\xa2\xc0"
+ "\x82\xa9\x39\xe3\x7f\xdc\xb8\x2e\xc9\x3e\xda\xc9\x7f\xf3\xad\x59\x50\xac"
+ "\xcf\xbc\x11\x1c\x76\xf1\xa9\x52\x94\x44\xe5\x6a\xaf\x68\xc5\x6c\x09\x2c"
+ "\xd3\x8d\xc3\xbe\xf5\xd2\x0a\x93\x99\x26\xed\x4f\x74\xa1\x3e\xdd\xfb\xe1"
+ "\xa1\xce\xcc\x48\x94\xaf\x94\x28\xc2\xb7\xb8\x88\x3f\xe4\x46\x3a\x4b\xc8"
+ "\x5b\x1c\xb3\xc1\x02\x41\x00\xee\xcf\xae\x81\xb1\xb9\xb3\xc9\x08\x81\x0b"
+ "\x10\xa1\xb5\x60\x01\x99\xeb\x9f\x44\xae\xf4\xfd\xa4\x93\xb8\x1a\x9e\x3d"
+ "\x84\xf6\x32\x12\x4e\xf0\x23\x6e\x5d\x1e\x3b\x7e\x28\xfa\xe7\xaa\x04\x0a"
+ "\x2d\x5b\x25\x21\x76\x45\x9d\x1f\x39\x75\x41\xba\x2a\x58\xfb\x65\x99\x02"
+ "\x41\x00\xc9\x7f\xb1\xf0\x27\xf4\x53\xf6\x34\x12\x33\xea\xaa\xd1\xd9\x35"
+ "\x3f\x6c\x42\xd0\x88\x66\xb1\xd0\x5a\x0f\x20\x35\x02\x8b\x9d\x86\x98\x40"
+ "\xb4\x16\x66\xb4\x2e\x92\xea\x0d\xa3\xb4\x32\x04\xb5\xcf\xce\x33\x52\x52"
+ "\x4d\x04\x16\xa5\xa4\x41\xe7\x00\xaf\x46\x15\x03\x02\x40\x54\x49\x4c\xa6"
+ "\x3e\xba\x03\x37\xe4\xe2\x40\x23\xfc\xd6\x9a\x5a\xeb\x07\xdd\xdc\x01\x83"
+ "\xa4\xd0\xac\x9b\x54\xb0\x51\xf2\xb1\x3e\xd9\x49\x09\x75\xea\xb7\x74\x14"
+ "\xff\x59\xc1\xf7\x69\x2e\x9a\x2e\x20\x2b\x38\xfc\x91\x0a\x47\x41\x74\xad"
+ "\xc9\x3c\x1f\x67\xc9\x81\x02\x40\x47\x1e\x02\x90\xff\x0a\xf0\x75\x03\x51"
+ "\xb7\xf8\x78\x86\x4c\xa9\x61\xad\xbd\x3a\x8a\x7e\x99\x1c\x5c\x05\x56\xa9"
+ "\x4c\x31\x46\xa7\xf9\x80\x3f\x8f\x6f\x8a\xe3\x42\xe9\x31\xfd\x8a\xe4\x7a"
+ "\x22\x0d\x1b\x99\xa4\x95\x84\x98\x07\xfe\x39\xf9\x24\x5a\x98\x36\xda\x3d"
+ "\x02\x41\x00\xb0\x6c\x4f\xda\xbb\x63\x01\x19\x8d\x26\x5b\xdb\xae\x94\x23"
+ "\xb3\x80\xf2\x71\xf7\x34\x53\x88\x50\x93\x07\x7f\xcd\x39\xe2\x11\x9f\xc9"
+ "\x86\x32\x15\x4f\x58\x83\xb1\x67\xa9\x67\xbf\x40\x2b\x4e\x9e\x2e\x0f\x96"
+ "\x56\xe6\x98\xea\x36\x66\xed\xfb\x25\x79\x80\x39\xf7";
+
+// kOAEPCiphertext3 is a sample encryption of |kPlaintext| with |kKey3| using
+// RSA OAEP.
+static const uint8_t kOAEPCiphertext3[] =
+ "\xb8\x24\x6b\x56\xa6\xed\x58\x81\xae\xb5\x85\xd9\xa2\x5b\x2a\xd7\x90\xc4"
+ "\x17\xe0\x80\x68\x1b\xf1\xac\x2b\xc3\xde\xb6\x9d\x8b\xce\xf0\xc4\x36\x6f"
+ "\xec\x40\x0a\xf0\x52\xa7\x2e\x9b\x0e\xff\xb5\xb3\xf2\xf1\x92\xdb\xea\xca"
+ "\x03\xc1\x27\x40\x05\x71\x13\xbf\x1f\x06\x69\xac\x22\xe9\xf3\xa7\x85\x2e"
+ "\x3c\x15\xd9\x13\xca\xb0\xb8\x86\x3a\x95\xc9\x92\x94\xce\x86\x74\x21\x49"
+ "\x54\x61\x03\x46\xf4\xd4\x74\xb2\x6f\x7c\x48\xb4\x2e\xe6\x8e\x1f\x57\x2a"
+ "\x1f\xc4\x02\x6a\xc4\x56\xb4\xf5\x9f\x7b\x62\x1e\xa1\xb9\xd8\x8f\x64\x20"
+ "\x2f\xb1";
+
+static const uint8_t kTwoPrimeKey[] =
+ "\x30\x82\x04\xa1\x02\x01\x00\x02\x82\x01\x01\x00\x93\x3a\x4f\xc9\x6a\x0a"
+ "\x6b\x28\x04\xfa\xb7\x05\x56\xdf\xa0\xaa\x4f\xaa\xab\x94\xa0\xa9\x25\xef"
+ "\xc5\x96\xd2\xd4\x66\x16\x62\x2c\x13\x7b\x91\xd0\x36\x0a\x10\x11\x6d\x7a"
+ "\x91\xb6\xe4\x74\x57\xc1\x3d\x7a\xbe\x24\x05\x3a\x04\x0b\x73\x91\x53\xb1"
+ "\x74\x10\xe1\x87\xdc\x91\x28\x9c\x1e\xe5\xf2\xb9\xfc\xa2\x48\x34\xb6\x78"
+ "\xed\x6d\x95\xfb\xf2\xc0\x4e\x1c\xa4\x15\x00\x3c\x8a\x68\x2b\xd6\xce\xd5"
+ "\xb3\x9f\x66\x02\xa7\x0d\x08\xa3\x23\x9b\xe5\x36\x96\x13\x22\xf9\x69\xa6"
+ "\x87\x88\x9b\x85\x3f\x83\x9c\xab\x1a\x1b\x6d\x8d\x16\xf4\x5e\xbd\xee\x4b"
+ "\x59\x56\xf8\x9d\x58\xcd\xd2\x83\x85\x59\x43\x84\x63\x4f\xe6\x1a\x86\x66"
+ "\x0d\xb5\xa0\x87\x89\xb6\x13\x82\x43\xda\x34\x92\x3b\x68\xc4\x95\x71\x2f"
+ "\x15\xc2\xe0\x43\x67\x3c\x08\x00\x36\x10\xc3\xb4\x46\x4c\x4e\x6e\xf5\x44"
+ "\xa9\x04\x44\x9d\xce\xc7\x05\x79\xee\x11\xcf\xaf\x2c\xd7\x9a\x32\xd3\xa5"
+ "\x30\xd4\x3a\x78\x43\x37\x74\x22\x90\x24\x04\x11\xd7\x95\x08\x52\xa4\x71"
+ "\x41\x68\x94\xb0\xa0\xc3\xec\x4e\xd2\xc4\x30\x71\x98\x64\x9c\xe3\x7c\x76"
+ "\xef\x33\xa3\x2b\xb1\x87\x63\xd2\x5c\x09\xfc\x90\x2d\x92\xf4\x57\x02\x01"
+ "\x03\x02\x82\x01\x00\x62\x26\xdf\xdb\x9c\x06\xf2\x1a\xad\xfc\x7a\x03\x8f"
+ "\x3f\xc0\x71\x8a\x71\xc7\xb8\x6b\x1b\x6e\x9f\xd9\x0f\x37\x38\x44\x0e\xec"
+ "\x1d\x62\x52\x61\x35\x79\x5c\x0a\xb6\x48\xfc\x61\x24\x98\x4d\x8f\xd6\x28"
+ "\xfc\x7e\xc2\xae\x26\xad\x5c\xf7\xb6\x37\xcb\xa2\xb5\xeb\xaf\xe8\x60\xc5"
+ "\xbd\x69\xee\xa1\xd1\x53\x16\xda\xcd\xce\xfb\x48\xf3\xb9\x52\xa1\xd5\x89"
+ "\x68\x6d\x63\x55\x7d\xb1\x9a\xc7\xe4\x89\xe3\xcd\x14\xee\xac\x6f\x5e\x05"
+ "\xc2\x17\xbd\x43\x79\xb9\x62\x17\x50\xf1\x19\xaf\xb0\x67\xae\x2a\x57\xbd"
+ "\xc7\x66\xbc\xf3\xb3\x64\xa1\xe3\x16\x74\x9e\xea\x02\x5c\xab\x94\xd8\x97"
+ "\x02\x42\x0c\x2c\xba\x54\xb9\xaf\xe0\x45\x93\xad\x7f\xb3\x10\x6a\x96\x50"
+ "\x4b\xaf\xcf\xc8\x27\x62\x2d\x83\xe9\x26\xc6\x94\xc1\xef\x5c\x8e\x06\x42"
+ "\x53\xe5\x56\xaf\xc2\x99\x01\xaa\x9a\x71\xbc\xe8\x21\x33\x2a\x2d\xa3\x36"
+ "\xac\x1b\x86\x19\xf8\xcd\x1f\x80\xa4\x26\x98\xb8\x9f\x62\x62\xd5\x1a\x7f"
+ "\xee\xdb\xdf\x81\xd3\x21\xdb\x33\x92\xee\xff\xe2\x2f\x32\x77\x73\x6a\x58"
+ "\xab\x21\xf3\xe3\xe1\xbc\x4f\x12\x72\xa6\xb5\xc2\xfb\x27\x9e\xc8\xca\xab"
+ "\x64\xa0\x87\x07\x9d\xef\xca\x0f\xdb\x02\x81\x81\x00\xe6\xd3\x4d\xc0\xa1"
+ "\x91\x0e\x62\xfd\xb0\xdd\xc6\x30\xb8\x8c\xcb\x14\xc1\x4b\x69\x30\xdd\xcd"
+ "\x86\x67\xcb\x37\x14\xc5\x03\xd2\xb4\x69\xab\x3d\xe5\x16\x81\x0f\xe5\x50"
+ "\xf4\x18\xb1\xec\xbc\x71\xe9\x80\x99\x06\xe4\xa3\xfe\x44\x84\x4a\x2d\x1e"
+ "\x07\x7f\x22\x70\x6d\x4f\xd4\x93\x0b\x8b\x99\xce\x1e\xab\xcd\x4c\xd2\xd3"
+ "\x10\x47\x5c\x09\x9f\x6d\x82\xc0\x08\x75\xe3\x3d\x83\xc2\x19\x50\x29\xec"
+ "\x1f\x84\x29\xcc\xf1\x56\xee\xbd\x54\x5d\xe6\x19\xdf\x0d\x1c\xa4\xbb\x0a"
+ "\xfe\x84\x44\x29\x1d\xf9\x5c\x80\x96\x5b\x24\xb4\xf7\x02\x1b\x02\x81\x81"
+ "\x00\xa3\x48\xf1\x9c\x58\xc2\x5f\x38\xfb\xd8\x12\x39\xf1\x8e\x73\xa1\xcf"
+ "\x78\x12\xe0\xed\x2a\xbb\xef\xac\x23\xb2\xbf\xd6\x0c\xe9\x6e\x1e\xab\xea"
+ "\x3f\x68\x36\xa7\x1f\xe5\xab\xe0\x86\xa5\x76\x32\x98\xdd\x75\xb5\x2b\xbc"
+ "\xcb\x8a\x03\x00\x7c\x2e\xca\xf8\xbc\x19\xe4\xe3\xa3\x31\xbd\x1d\x20\x2b"
+ "\x09\xad\x6f\x4c\xed\x48\xd4\xdf\x87\xf9\xf0\x46\xb9\x86\x4c\x4b\x71\xe7"
+ "\x48\x78\xdc\xed\xc7\x82\x02\x44\xd3\xa6\xb3\x10\x5f\x62\x81\xfc\xb8\xe4"
+ "\x0e\xf4\x1a\xdd\xab\x3f\xbc\x63\x79\x5b\x39\x69\x5e\xea\xa9\x15\xfe\x90"
+ "\xec\xda\x75\x02\x81\x81\x00\x99\xe2\x33\xd5\xc1\x0b\x5e\xec\xa9\x20\x93"
+ "\xd9\x75\xd0\x5d\xdc\xb8\x80\xdc\xf0\xcb\x3e\x89\x04\x45\x32\x24\xb8\x83"
+ "\x57\xe1\xcd\x9b\xc7\x7e\x98\xb9\xab\x5f\xee\x35\xf8\x10\x76\x9d\xd2\xf6"
+ "\x9b\xab\x10\xaf\x43\x17\xfe\xd8\x58\x31\x73\x69\x5a\x54\xc1\xa0\x48\xdf"
+ "\xe3\x0c\xb2\x5d\x11\x34\x14\x72\x88\xdd\xe1\xe2\x0a\xda\x3d\x5b\xbf\x9e"
+ "\x57\x2a\xb0\x4e\x97\x7e\x57\xd6\xbb\x8a\xc6\x9d\x6a\x58\x1b\xdd\xf6\x39"
+ "\xf4\x7e\x38\x3e\x99\x66\x94\xb3\x68\x6d\xd2\x07\x54\x58\x2d\x70\xbe\xa6"
+ "\x3d\xab\x0e\xe7\x6d\xcd\xfa\x01\x67\x02\x81\x80\x6c\xdb\x4b\xbd\x90\x81"
+ "\x94\xd0\xa7\xe5\x61\x7b\xf6\x5e\xf7\xc1\x34\xfa\xb7\x40\x9e\x1c\x7d\x4a"
+ "\x72\xc2\x77\x2a\x8e\xb3\x46\x49\x69\xc7\xf1\x7f\x9a\xcf\x1a\x15\x43\xc7"
+ "\xeb\x04\x6e\x4e\xcc\x65\xe8\xf9\x23\x72\x7d\xdd\x06\xac\xaa\xfd\x74\x87"
+ "\x50\x7d\x66\x98\x97\xc2\x21\x28\xbe\x15\x72\x06\x73\x9f\x88\x9e\x30\x8d"
+ "\xea\x5a\xa6\xa0\x2f\x26\x59\x88\x32\x4b\xef\x85\xa5\xe8\x9e\x85\x01\x56"
+ "\xd8\x8d\x19\xcc\xb5\x94\xec\x56\xa8\x7b\x42\xb4\xa2\xbc\x93\xc7\x7f\xd2"
+ "\xec\xfb\x92\x26\x46\x3f\x47\x1b\x63\xff\x0b\x48\x91\xa3\x02\x81\x80\x2c"
+ "\x4a\xb9\xa4\x46\x7b\xff\x50\x7e\xbf\x60\x47\x3b\x2b\x66\x82\xdc\x0e\x53"
+ "\x65\x71\xe9\xda\x2a\xb8\x32\x93\x42\xb7\xff\xea\x67\x66\xf1\xbc\x87\x28"
+ "\x65\x29\x79\xca\xab\x93\x56\xda\x95\xc1\x26\x44\x3d\x27\xc1\x91\xc6\x9b"
+ "\xd9\xec\x9d\xb7\x49\xe7\x16\xee\x99\x87\x50\x95\x81\xd4\x5c\x5b\x5a\x5d"
+ "\x0a\x43\xa5\xa7\x8f\x5a\x80\x49\xa0\xb7\x10\x85\xc7\xf4\x42\x34\x86\xb6"
+ "\x5f\x3f\x88\x9e\xc7\xf5\x59\x29\x39\x68\x48\xf2\xd7\x08\x5b\x92\x8e\x6b"
+ "\xea\xa5\x63\x5f\xc0\xfb\xe4\xe1\xb2\x7d\xb7\x40\xe9\x55\x06\xbf\x58\x25"
+ "\x6f";
+
+static const uint8_t kTwoPrimeEncryptedMessage[] = {
+ 0x63, 0x0a, 0x30, 0x45, 0x43, 0x11, 0x45, 0xb7, 0x99, 0x67, 0x90, 0x35,
+ 0x37, 0x27, 0xff, 0xbc, 0xe0, 0xbf, 0xa6, 0xd1, 0x47, 0x50, 0xbb, 0x6c,
+ 0x1c, 0xaa, 0x66, 0xf2, 0xff, 0x9d, 0x9a, 0xa6, 0xb4, 0x16, 0x63, 0xb0,
+ 0xa1, 0x7c, 0x7c, 0x0c, 0xef, 0xb3, 0x66, 0x52, 0x42, 0xd7, 0x5e, 0xf3,
+ 0xa4, 0x15, 0x33, 0x40, 0x43, 0xe8, 0xb1, 0xfc, 0xe0, 0x42, 0x83, 0x46,
+ 0x28, 0xce, 0xde, 0x7b, 0x01, 0xeb, 0x28, 0x92, 0x70, 0xdf, 0x8d, 0x54,
+ 0x9e, 0xed, 0x23, 0xb4, 0x78, 0xc3, 0xca, 0x85, 0x53, 0x48, 0xd6, 0x8a,
+ 0x87, 0xf7, 0x69, 0xcd, 0x82, 0x8c, 0x4f, 0x5c, 0x05, 0x55, 0xa6, 0x78,
+ 0x89, 0xab, 0x4c, 0xd8, 0xa9, 0xd6, 0xa5, 0xf4, 0x29, 0x4c, 0x23, 0xc8,
+ 0xcf, 0xf0, 0x4c, 0x64, 0x6b, 0x4e, 0x02, 0x17, 0x69, 0xd6, 0x47, 0x83,
+ 0x30, 0x43, 0x02, 0x29, 0xda, 0xda, 0x75, 0x3b, 0xd7, 0xa7, 0x2b, 0x31,
+ 0xb3, 0xe9, 0x71, 0xa4, 0x41, 0xf7, 0x26, 0x9b, 0xcd, 0x23, 0xfa, 0x45,
+ 0x3c, 0x9b, 0x7d, 0x28, 0xf7, 0xf9, 0x67, 0x04, 0xba, 0xfc, 0x46, 0x75,
+ 0x11, 0x3c, 0xd5, 0x27, 0x43, 0x53, 0xb1, 0xb6, 0x9e, 0x18, 0xeb, 0x11,
+ 0xb4, 0x25, 0x20, 0x30, 0x0b, 0xe0, 0x1c, 0x17, 0x36, 0x22, 0x10, 0x0f,
+ 0x99, 0xb5, 0x50, 0x14, 0x73, 0x07, 0xf0, 0x2f, 0x5d, 0x4c, 0xe3, 0xf2,
+ 0x86, 0xc2, 0x05, 0xc8, 0x38, 0xed, 0xeb, 0x2a, 0x4a, 0xab, 0x76, 0xe3,
+ 0x1a, 0x75, 0x44, 0xf7, 0x6e, 0x94, 0xdc, 0x25, 0x62, 0x7e, 0x31, 0xca,
+ 0xc2, 0x73, 0x51, 0xb5, 0x03, 0xfb, 0xf9, 0xf6, 0xb5, 0x8d, 0x4e, 0x6c,
+ 0x21, 0x0e, 0xf9, 0x97, 0x26, 0x57, 0xf3, 0x52, 0x72, 0x07, 0xf8, 0xb4,
+ 0xcd, 0xb4, 0x39, 0xcf, 0xbf, 0x78, 0xcc, 0xb6, 0x87, 0xf9, 0xb7, 0x8b,
+ 0x6a, 0xce, 0x9f, 0xc8,
+};
+
+static const uint8_t kThreePrimeKey[] =
+ "\x30\x82\x04\xd7\x02\x01\x01\x02\x82\x01\x00\x62\x91\xe9\xea\xb3\x5d\x6c"
+ "\x29\xae\x21\x83\xbb\xb5\x82\xb1\x9e\xea\xe0\x64\x5b\x1e\x2f\x5e\x2c\x0a"
+ "\x80\x3d\x29\xd4\xfa\x9a\xe7\x44\xe6\x21\xbd\x98\xc0\x3d\xe0\x53\x59\xae"
+ "\xd3\x3e\xfe\xc4\xc2\xc4\x5a\x5a\x89\x07\xf4\x4f\xdc\xb0\x6a\xd4\x3e\x99"
+ "\x7d\x7a\x97\x26\x4e\xe1\x93\xca\x6e\xed\x07\xfc\xb4\xfa\x95\x1e\x73\x7b"
+ "\x86\x08\x6a\xb9\xd4\x29\xb0\x7e\x59\xb7\x9d\x7b\xeb\x67\x6e\xf0\xbb\x5e"
+ "\xcf\xb9\xcd\x58\x93\xf0\xe7\x88\x17\x6c\x0d\x76\x1e\xb9\x27\x9a\x4d\x02"
+ "\x16\xb6\x49\x6d\xa7\x83\x23\x4d\x02\x48\x0c\x0c\x1f\x0e\x85\x21\xe3\x06"
+ "\x76\x0a\x73\xe6\xc1\x21\xfa\x30\x18\x78\x29\x5c\x31\xd0\x29\xae\x6f\x7d"
+ "\x87\xd8\x2f\x16\xfa\xbc\x67\x8a\x94\x71\x59\x9b\xec\x22\x40\x55\x9f\xc2"
+ "\x94\xb5\xbd\x78\x01\xc9\xef\x18\xc8\x6d\x0d\xdc\x53\x42\xb2\x5c\xab\x65"
+ "\x05\xbd\x35\x08\x85\x1b\xf8\xe9\x47\xbc\xfe\xc5\xae\x47\x29\x63\x44\x8e"
+ "\x4d\xb7\x47\xab\x0d\xd8\x76\x68\x4f\xc7\x07\x02\xe4\x86\xb0\xcf\xd8\x19"
+ "\xad\xf4\x85\x76\x8b\x3b\x4e\x40\x8d\x29\x7a\x8a\x07\x36\xf3\x78\xae\x17"
+ "\xa6\x8f\x53\x58\x65\x4c\x86\x9e\xd7\x8b\xec\x38\x4f\x99\xc7\x02\x01\x03"
+ "\x02\x82\x01\x00\x41\xb6\x9b\xf1\xcc\xe8\xf2\xc6\x74\x16\x57\xd2\x79\x01"
+ "\xcb\xbf\x47\x40\x42\xe7\x69\x74\xe9\x72\xb1\xaa\xd3\x71\x38\xa7\x11\xef"
+ "\x83\x44\x16\x7e\x65\xd5\x7e\x95\x8c\xe6\x74\x8c\xd4\xa9\xd8\x81\xd8\x3c"
+ "\x3c\x5b\x5a\xa2\xdf\xe8\x75\x9c\x8d\x7f\x10\xfe\x51\xba\x19\x89\xeb\xb7"
+ "\xdc\x49\xf3\x5a\xa8\x78\xa7\x0e\x14\x4c\xfd\x04\x05\x9c\x7b\xe2\xc5\xa3"
+ "\x04\xee\xd9\x4c\xfd\x7d\x47\xb0\x0d\x9b\x3d\x70\x91\x81\x2c\xab\x2b\x87"
+ "\xad\x11\x68\x24\xfc\x2b\xd4\xee\x5e\x28\xeb\x6d\xab\xde\x0f\x77\x15\x58"
+ "\x76\x39\xc9\x59\x3a\x7f\x19\x9d\xc6\x7e\x86\xe4\xd5\x38\x70\x9e\xae\xb9"
+ "\xfb\x33\x33\xd1\x0c\x2d\xab\x01\x20\xe1\x8b\x29\x99\xd3\xeb\x87\x05\x72"
+ "\xaa\x43\x58\x64\x8e\x9e\x31\xdb\x45\x9b\x2b\xac\x58\x80\x5d\x33\xa2\x43"
+ "\x05\x96\xcc\xca\x2d\x04\x5f\xd6\xb7\x3d\x8b\x8f\x2d\xa3\xa5\xf8\x73\xf5"
+ "\xd7\xc0\x19\xff\x10\xe6\xee\x3a\x26\x2f\xe1\x64\x3d\x11\xcd\x2d\xe4\x0a"
+ "\x84\x27\xe3\xcb\x16\x62\x19\xe7\xe3\x0d\x13\xe8\x09\x5a\x53\xd0\x20\x56"
+ "\x15\xf5\xb3\x67\xac\xa1\xb5\x94\x6b\xab\xdc\x71\xc7\xbf\x0a\xde\x76\xf5"
+ "\x03\xa0\x30\xd8\x27\x9d\x00\x2b\x02\x57\x00\xf1\x4f\xc2\x86\x13\x06\x17"
+ "\xf7\x69\x7e\x37\xdf\x67\xc5\x32\xa0\x74\x1c\x32\x69\x0f\x9f\x08\x88\x24"
+ "\xb1\x51\xbc\xbc\x92\xba\x73\x1f\x9c\x75\xc2\x14\x6d\x4f\xc4\x5a\xcf\xda"
+ "\x44\x35\x00\x6b\x42\x3b\x9f\x14\xf1\x05\xb3\x51\x22\xb6\xbe\x9c\xe0\xc1"
+ "\x5c\x48\x61\xdf\x4e\x4c\x72\xb8\x05\x35\x7c\xac\xf1\xbb\xa0\x3b\x2a\xea"
+ "\xf7\x86\xe9\xd2\xff\x1e\x1d\x02\x56\x00\xca\xb1\x39\xf6\xa2\xc6\x3b\x65"
+ "\x45\x2f\x39\x00\xcd\x6e\xd6\x55\xf7\x71\x37\x89\xc2\xe7\x7a\xc0\x1a\xa6"
+ "\x2f\xea\x17\x7c\xaa\x2a\x91\x8f\xd4\xc7\x50\x8b\xab\x8e\x99\x3b\x33\x91"
+ "\xbc\x02\x10\x58\x4b\x58\x40\x9b\xc4\x8f\x48\x2b\xa7\x44\xfd\x07\x04\xf0"
+ "\x98\x67\x56\xea\x25\x92\x8b\x2e\x4b\x4a\xa1\xd3\xc2\xa4\xb4\x9b\x59\x70"
+ "\x32\xa6\xd8\x8b\xd9\x02\x57\x00\xa0\xdf\xd7\x04\x0c\xae\xba\xa4\xf0\xfe"
+ "\xcf\xea\x45\x2e\x21\xc0\x4d\x68\x21\x9b\x5f\xbf\x5b\x05\x6d\xcb\x8b\xd3"
+ "\x28\x61\xd1\xa2\x15\x12\xf9\x2c\x0d\x9e\x35\x2d\x91\xdf\xe6\xd8\x23\x55"
+ "\x9c\xd6\xd2\x6a\x0d\xf6\x03\xcc\xe0\xc1\xcf\x29\xbd\xeb\x2b\x92\xda\xeb"
+ "\xea\x34\x32\xf7\x25\x58\xce\x53\x1d\xf6\x7d\x15\x7c\xc7\x47\x4f\xaf\x46"
+ "\x8c\xaa\x14\x13\x02\x56\x00\x87\x20\xd1\x4f\x17\x2e\xd2\x43\x83\x74\xd0"
+ "\xab\x33\x9f\x39\x8e\xa4\xf6\x25\x06\x81\xef\xa7\x2a\xbc\x6e\xca\x9c\x0f"
+ "\xa8\x71\x71\xb6\x5f\xe3\x2f\x8b\x07\xc7\xb4\x66\x27\x77\xb6\x7d\x56\xb5"
+ "\x90\x32\x3a\xd5\xbd\x2d\xb4\xda\xc7\xc4\xd8\xa8\xaf\x58\xa0\x65\x9a\x39"
+ "\xf1\x6e\x61\xb2\x1e\xdc\xdc\x6b\xe2\x81\xc3\x23\x12\x3b\xa0\x21\xc4\x90"
+ "\x5d\x3b\x02\x57\x00\xe6\x8a\xaa\xb8\x6d\x2c\x81\x43\xb5\xd6\xa0\x2b\x42"
+ "\x49\xa9\x0a\x51\xfa\x18\xc8\x32\xea\x54\x18\xf3\x60\xc2\xb5\x4a\x43\x05"
+ "\x93\x9c\x01\xd9\x28\xed\x73\xfa\x82\xbc\x12\x64\xcb\xc4\x24\xa9\x3e\xae"
+ "\x7c\x4b\x8f\x94\x57\x7b\x14\x10\x41\xdc\x62\x12\x8c\xb2\x4a\x7c\xf6\x53"
+ "\xd4\xc6\xe4\xda\xd1\xa2\x00\x0e\x3d\x30\xf7\x05\x4f\x1d\x82\xbc\x52\xd9"
+ "\xb1\x30\x82\x01\x0a\x30\x82\x01\x06\x02\x56\x00\x84\x12\x4f\xf7\x3b\x65"
+ "\x53\x34\x6c\x6c\x4d\x77\xdf\xfd\x1f\xb6\x16\xe2\x25\x15\xca\xc9\xc1\x41"
+ "\x9a\x50\xda\xeb\x88\x4f\x3d\xb3\x01\x00\x44\xc4\xac\xe7\x14\x62\xa6\x56"
+ "\xde\xc5\xb7\xc3\x1d\x07\xbd\x7d\x64\xc5\x7e\x45\x25\x56\xed\x7a\xd2\x14"
+ "\xdb\x4e\x27\xd4\x1f\xf8\x94\xa7\xef\x07\xce\xdb\x24\xb7\xdd\x71\x5c\x63"
+ "\xc9\x33\xfe\xde\x40\x52\xeb\x02\x55\x58\x0c\x35\x4f\x7c\xee\x37\x78\x48"
+ "\x48\x33\xa5\x3f\xfe\x15\x24\x0f\x41\x6e\x0e\x87\x31\x2b\x81\x11\x8b\x3c"
+ "\x9d\x05\x8a\x29\x22\x00\xaa\xd8\x83\x1d\xef\x62\xec\x6e\xe4\x94\x83\xcf"
+ "\xd7\x68\xaf\xd3\xa8\xed\xd8\xfe\xd8\xc3\x8f\x48\xfc\x8c\x0d\xe7\x89\x6f"
+ "\xe2\xbf\xfb\x0d\xc5\x4a\x05\x34\x92\x18\x7a\x93\xa0\xe8\x42\x86\x22\xa9"
+ "\xe9\x80\x37\x47\x02\x55\x60\x76\xab\xde\x2b\xf5\xa2\x2c\xaa\x0c\x99\x81"
+ "\xee\x72\x2c\x7d\x22\x59\x2a\x35\xea\x50\x4e\x47\x6b\x92\x2d\x30\xa1\x01"
+ "\xa5\x9e\x26\x6e\x27\xca\xf5\xf2\x87\x5d\x31\xaf\xe9\x32\xcd\x10\xfd\x4d"
+ "\xdb\xf9\x86\x05\x12\x1b\x01\x84\x55\x97\x5f\xe2\x78\x27\xd9\xe4\x26\x7d"
+ "\xab\x0e\xe0\x1b\x6f\xcb\x4b\x14\xdd\xdc\xdc\x8b\xe8\x9f\xd0\x62\x96\xca"
+ "\xcf";
+
+static const uint8_t kThreePrimeEncryptedMessage[] = {
+ 0x58, 0xd9, 0xea, 0x8a, 0xf6, 0x3d, 0xb4, 0xd9, 0xf7, 0xbb, 0x02, 0xc5,
+ 0x58, 0xd2, 0xa9, 0x46, 0x80, 0x70, 0x70, 0x16, 0x07, 0x64, 0x32, 0x4c,
+ 0x4e, 0x92, 0x61, 0xb7, 0xff, 0x92, 0xdc, 0xfc, 0xf8, 0xf0, 0x2c, 0x84,
+ 0x56, 0xbc, 0xe5, 0x93, 0x76, 0xe5, 0xa3, 0x72, 0x98, 0xf2, 0xdf, 0xef,
+ 0x99, 0x53, 0xf6, 0xd8, 0x4b, 0x09, 0xac, 0xa9, 0xa3, 0xdb, 0x63, 0xa1,
+ 0xb5, 0x09, 0x8e, 0x40, 0x84, 0x8f, 0x4d, 0xd5, 0x1d, 0xac, 0x6c, 0xaa,
+ 0x6b, 0x15, 0xe7, 0xb1, 0x0c, 0x67, 0xd2, 0xb2, 0x81, 0x58, 0x30, 0x0e,
+ 0x18, 0x27, 0xa1, 0x9b, 0x96, 0xad, 0xae, 0x76, 0x1a, 0x32, 0xf7, 0x10,
+ 0x0b, 0x53, 0x85, 0x31, 0xd6, 0x2a, 0xf6, 0x1c, 0x9f, 0xc2, 0xc7, 0xb1,
+ 0x05, 0x63, 0x0b, 0xa5, 0x07, 0x1f, 0x1c, 0x01, 0xf0, 0xe0, 0x06, 0xea,
+ 0x20, 0x69, 0x41, 0x19, 0x57, 0x92, 0x17, 0xf7, 0x0c, 0x5c, 0x66, 0x75,
+ 0x0e, 0xe5, 0xb3, 0xf1, 0x67, 0x3b, 0x27, 0x47, 0xb2, 0x8e, 0x1c, 0xb6,
+ 0x3f, 0xdd, 0x76, 0x42, 0x31, 0x13, 0x68, 0x96, 0xdf, 0x3b, 0xd4, 0x87,
+ 0xd9, 0x16, 0x44, 0x71, 0x52, 0x2e, 0x54, 0x3e, 0x09, 0xcd, 0x71, 0xc1,
+ 0x1e, 0x5e, 0x96, 0x13, 0xc9, 0x1e, 0xa4, 0xe6, 0xe6, 0x97, 0x2c, 0x6b,
+ 0xf2, 0xa9, 0x5c, 0xc6, 0x60, 0x2a, 0xbc, 0x82, 0xf8, 0xcb, 0xd4, 0xd7,
+ 0xea, 0x8a, 0xa1, 0x8a, 0xd9, 0xa5, 0x14, 0x8b, 0x9e, 0xf9, 0x25, 0x02,
+ 0xd2, 0xab, 0x0c, 0x42, 0xca, 0x2d, 0x45, 0xa3, 0x56, 0x5e, 0xa2, 0x2a,
+ 0xc8, 0x60, 0xa5, 0x87, 0x5d, 0x85, 0x5c, 0xde, 0xc7, 0xa2, 0x47, 0xc3,
+ 0x99, 0x29, 0x23, 0x79, 0x36, 0x88, 0xad, 0x40, 0x3e, 0x27, 0x7d, 0xf0,
+ 0xb6, 0xfa, 0x95, 0x20, 0x3c, 0xec, 0xfc, 0x56, 0x3b, 0x20, 0x91, 0xee,
+ 0x98, 0x10, 0x2c, 0x82,
+};
+
+static const uint8_t kSixPrimeKey[] =
+ "\x30\x82\x05\x20\x02\x01\x01\x02\x82\x01\x00\x1c\x04\x39\x44\xb9\xb8\x71"
+ "\x1c\x1c\xf7\xdc\x11\x1b\x85\x3b\x2b\xe8\xa6\xeb\xeb\xe9\xb6\x86\x97\x73"
+ "\x5d\x75\x46\xd1\x35\x25\xf8\x30\x9a\xc3\x57\x44\x89\xa6\x44\x59\xe3\x3a"
+ "\x60\xb5\x33\x84\x72\xa4\x03\xc5\x1a\x20\x98\x70\xbd\xe8\x3b\xc1\x9b\x8a"
+ "\x3a\x24\x45\xb6\x6a\x73\xb4\xd0\x6c\x18\xc6\xa7\x94\xd3\x24\x70\xf0\x2d"
+ "\x0c\xa5\xb2\x3b\xc5\x33\x90\x9d\x56\x8d\x33\xf6\x93\x7d\xa7\x95\x88\x05"
+ "\xdf\xf5\x65\x58\xb9\x5b\xd3\x07\x9c\x16\x8e\x74\xfc\xb8\x76\xaf\x62\x99"
+ "\x6c\xd4\xc5\xb3\x69\xe5\x64\xdf\x38\x00\x25\x24\xe9\xb1\x4a\x85\xa6\xf4"
+ "\xb6\x23\x68\x67\x4a\x2c\xbd\x9d\x01\x3b\x04\x8c\x70\x94\x82\x76\x45\x0c"
+ "\x8b\x95\x8a\x07\x1c\x32\xe7\x09\x97\x3a\xfd\xca\x57\xe9\x57\x0c\xae\x2b"
+ "\xa3\x25\xd1\xf2\x0d\x34\xa1\xe6\x2f\x7b\x1b\x36\x53\x83\x95\xb9\x26\x6e"
+ "\x4f\x36\x26\xf8\x47\xae\xdf\xe8\x4d\xf6\xb2\xff\x03\x23\x74\xfa\xa5\x6d"
+ "\xcb\xcb\x80\x12\xc3\x77\xf0\x19\xb7\xf2\x6b\x19\x5c\xde\x0a\xd7\xee\x8c"
+ "\x48\x2f\x50\x24\xa5\x2e\xcc\x2a\xed\xc2\x35\xe0\x3d\x29\x31\x17\xd6\x8f"
+ "\x44\xaa\x5b\x33\xbd\xb4\x88\x87\xd9\x29\x3f\x94\xe7\x75\xe3\x02\x01\x03"
+ "\x02\x82\x01\x00\x12\xad\x7b\x83\x26\x7a\xf6\x12\xbd\xfa\x92\xb6\x12\x58"
+ "\xd2\x1d\x45\xc4\x9d\x47\xf1\x24\x59\xba\x4c\xe8\xf8\xd9\xe0\xce\x19\x50"
+ "\x20\x67\x2c\xe4\xd8\x5b\xc4\x2d\x91\x41\xeb\x05\x4f\xf4\xb4\x20\xc7\xbc"
+ "\xd6\xe2\x5c\xa0\x27\xcf\xb8\xb3\x3b\x5c\xeb\x5e\x96\xb7\x99\x4b\x8a\xc3"
+ "\x70\xaf\x7f\xd8\x5f\xeb\xcb\x1a\x79\x44\x68\x97\x84\xd8\x29\x87\x64\xba"
+ "\x18\x2e\x95\x66\x1a\x7d\xd9\x35\x3a\x5c\x92\x7a\x81\x1b\x6c\xa9\xf8\xfa"
+ "\x05\x23\x18\x5b\xb2\xf8\x77\x1c\xc5\x1b\x7d\x26\x5f\x48\x69\x1b\xc4\x34"
+ "\xef\x6e\xa1\x15\xd2\xb2\xac\xb8\xa8\xed\x1e\xee\xdc\xb5\xb9\x5c\x79\x25"
+ "\x48\xbb\xe5\x9d\xd8\xe5\xe2\x94\xdf\xd5\x32\x22\x84\xbf\xc2\xaa\xa4\x54"
+ "\xbb\x29\xdb\x13\x4a\x28\x3d\x83\x3a\xff\xa3\xae\x38\x08\xfc\x36\x84\x91"
+ "\x30\xd1\xfd\x82\x64\xf1\x0f\xae\xba\xd7\x9a\x43\x58\x03\x5e\x5f\x01\xcb"
+ "\x8b\x90\x8d\x77\x34\x6f\x37\x40\xb6\x6d\x22\x23\x90\xb2\xfd\x32\xb5\x96"
+ "\x45\xbf\xae\x8c\xc4\x62\x03\x6c\x68\x90\x59\x31\x1a\xcb\xfb\xa4\x0b\x94"
+ "\x15\x13\xda\x1a\x8d\xa7\x0b\x34\x62\x93\xea\xbe\x6e\x71\xc2\x1d\xc8\x9d"
+ "\xac\x66\xcc\x31\x87\xff\x99\xab\x02\x2c\x00\xa5\x57\x41\x66\x87\x68\x02"
+ "\x6a\xdf\x97\xb0\xfe\x6b\x34\xc4\x33\x88\x2b\xce\x82\xaf\x2d\x33\x5a\xad"
+ "\x75\x2d\xac\xa5\xd6\x3a\x2d\x65\x43\x68\xfb\x44\x9e\xb8\x25\x05\xed\x97"
+ "\x02\x2c\x00\xd2\x77\x34\x24\xac\x60\x9a\xc4\x68\x34\xe5\x6a\xa3\xdc\xe2"
+ "\xb0\x58\x5c\x35\x83\x5a\xc7\xa7\xc1\x0b\x7e\x9e\xa5\x85\x32\x47\x93\x22"
+ "\xee\xb6\x59\xe9\xe3\x61\x94\xd0\x0e\xcb\x02\x2b\x6e\x3a\x2b\x99\xaf\x9a"
+ "\xac\x47\x3f\xba\x75\xfe\xf2\x23\x2d\x77\xb0\x1d\x34\x57\x1f\x73\x77\x91"
+ "\xc8\xf8\xc9\x1d\xc3\xe4\x26\xc8\xee\x2c\xf0\xa7\x83\x14\x7a\xc3\x59\x49"
+ "\x0f\x02\x2c\x00\x8c\x4f\x78\x18\x72\xeb\x11\xd8\x45\x78\x98\xf1\xc2\x93"
+ "\x41\xca\xe5\x92\xce\x57\x91\xda\x6f\xd6\x07\xa9\xbf\x19\x03\x76\xda\x62"
+ "\x17\x49\xce\xe6\x9b\xec\xeb\xb8\x8a\xb4\x87\x02\x2c\x00\xa3\xc2\x29\xa6"
+ "\xa7\xe1\x3c\xe9\xcf\x0f\x50\x51\x1c\xcc\xc8\x5b\x08\x9c\x97\x24\x3a\x86"
+ "\x23\xa8\x0b\xbb\x54\xa6\xb9\x70\x3d\x1d\xd0\x1b\xa3\xac\xd9\xb2\x03\x80"
+ "\xd7\x67\xec\x30\x82\x02\x29\x30\x81\x88\x02\x2c\x00\x97\x5d\x3b\xf2\xcc"
+ "\xba\xd9\x77\x67\xaa\xd2\x22\xa7\xa3\x49\x08\xc7\xb8\x27\xa1\x59\x4b\xa7"
+ "\xa5\xd2\x74\x05\xe7\x5a\x35\xd7\x25\x79\x18\x20\x8a\x25\xec\x3b\x52\xaf"
+ "\xcb\xdb\x02\x2b\x64\xe8\xd2\xa1\xdd\xd1\xe6\x4f\x9a\x71\xe1\x6c\x6f\xc2"
+ "\x30\xb0\x85\x25\x6f\xc0\xe6\x32\x6f\xc3\xe1\xa2\xae\x9a\x3c\x23\xe4\xc3"
+ "\xa6\x10\x15\xb1\x6e\x9d\x7c\xe1\xca\x87\xe7\x02\x2b\x5e\xef\x25\x29\xed"
+ "\xf6\x52\x15\xd3\x60\xb6\x88\xcf\x0f\xe2\x24\xa4\x04\x97\x9c\x9d\x58\x13"
+ "\xbb\x00\x6d\x39\xf6\xad\x21\x7e\x56\x2c\x2e\x06\x06\xc4\x6d\x44\xac\x79"
+ "\x1f\xe5\x30\x81\x89\x02\x2c\x00\xdb\xf1\x78\xf9\xa4\x94\xea\x39\x8a\x3f"
+ "\x23\x48\x2a\x23\x8f\xd2\x18\x97\xd2\xdf\x0f\xb8\x2b\x33\xa0\xe8\x8f\xbc"
+ "\x4e\x42\xfd\x54\xc7\x0f\xde\xba\x6d\xba\x96\xa7\xce\x67\x3d\x02\x2c\x00"
+ "\x92\xa0\xfb\x51\x18\x63\x46\xd1\x06\xd4\xc2\x30\x1c\x17\xb5\x36\xbb\x0f"
+ "\xe1\xea\x0a\x7a\xc7\x77\xc0\x9b\x0a\x7d\x89\x81\xfe\x38\x84\xb5\x3f\x26"
+ "\xf3\xd1\xb9\xc5\x34\x44\xd3\x02\x2b\x4c\xbd\x1d\x44\xc8\x19\x23\xd8\xb3"
+ "\x96\x66\x4b\x62\xcb\x3e\xe6\x6c\x11\xdf\xb2\x92\xd3\xc8\x34\xb9\xa6\x5a"
+ "\x2f\x19\xf4\x0b\xb2\xe6\x8e\xa6\xaf\xa3\xae\xa4\xb3\x92\xc4\x79\x30\x81"
+ "\x85\x02\x2b\x00\x89\xab\x30\xfc\x7b\x37\x94\x11\x9f\x4d\x31\x3b\xac\x09"
+ "\x57\xe6\x64\xec\xa0\xc8\xf8\x04\x1a\xf9\x2a\xa4\x4b\x36\x18\xbb\x5f\xdc"
+ "\xcd\xf0\xc8\xcb\x97\xd1\xdf\x13\x12\x3f\x02\x2a\x5b\xc7\x75\xfd\xa7\x7a"
+ "\x62\xb6\x6a\x33\x76\x27\xc8\x06\x3a\x99\x98\x9d\xc0\x85\xfa\xad\x67\x50"
+ "\xc7\x18\x32\x24\x10\x7c\xea\x93\x33\xf5\xdb\x32\x65\x36\x94\xb7\x61\x7f"
+ "\x02\x2a\x16\x6c\x96\xa1\x50\x6f\x3a\x92\xc0\x75\x43\xb5\x6b\x9c\x17\x09"
+ "\xd3\xf0\x67\x69\x45\x92\xfb\x7b\x50\xa8\x42\x9b\x33\x92\xab\xd5\xe6\x49"
+ "\xb3\x26\x99\x55\x16\x3a\x39\x63\x30\x81\x87\x02\x2b\x00\xc1\x25\x19\x1d"
+ "\x6e\x18\xcb\x2d\x64\xe2\xe6\xb6\x1c\xe4\xaa\x9c\xb9\xee\x18\xd4\xf7\x5f"
+ "\x66\x40\xf0\xe1\x31\x38\xf2\x53\x00\x8b\xcc\xe4\x0d\xb7\x81\xb4\xe6\x1c"
+ "\x19\xaf\x02\x2b\x00\x80\xc3\x66\x13\x9e\xbb\x32\x1e\x43\x41\xef\x24\x13"
+ "\x43\x1c\x68\x7b\xf4\x10\x8d\xfa\x3f\x99\x80\xa0\x96\x20\xd0\xa1\x8c\xab"
+ "\x07\xdd\xed\x5e\x7a\x56\x78\x99\x68\x11\x1f\x02\x2b\x00\xb0\x59\xea\x67"
+ "\x93\x42\xbf\x07\x54\x38\x41\xcb\x73\xa4\x0e\xc2\xae\x56\x19\x41\xc9\x8a"
+ "\xb2\x2f\xa8\x0a\xb1\x4e\x12\x39\x2e\xc0\x94\x9a\xc6\xa3\xe4\xaf\x8a\x16"
+ "\x06\xb8";
+
+static const uint8_t kSixPrimeEncryptedMessage[] = {
+ 0x0a, 0xcb, 0x6c, 0x02, 0x9d, 0x1a, 0x7c, 0xf3, 0x4e, 0xff, 0x16, 0x88,
+ 0xee, 0x22, 0x1d, 0x8d, 0xd2, 0xfd, 0xde, 0x83, 0xb3, 0xd9, 0x35, 0x2c,
+ 0x82, 0xe0, 0xff, 0xe6, 0x79, 0x6d, 0x06, 0x21, 0x74, 0xa8, 0x04, 0x0c,
+ 0xe2, 0xd3, 0x98, 0x3f, 0xbf, 0xd0, 0xe9, 0x88, 0x24, 0xe2, 0x05, 0xa4,
+ 0x45, 0x51, 0x87, 0x6b, 0x1c, 0xef, 0x5f, 0x2d, 0x61, 0xb6, 0xf1, 0x4c,
+ 0x1f, 0x3d, 0xbf, 0x4b, 0xf2, 0xda, 0x09, 0x97, 0x81, 0xde, 0x91, 0xb7,
+ 0x0d, 0xb4, 0xc2, 0xab, 0x41, 0x64, 0x9d, 0xd9, 0x39, 0x46, 0x79, 0x66,
+ 0x43, 0xf1, 0x34, 0x21, 0x56, 0x2f, 0xc6, 0x68, 0x40, 0x4a, 0x2d, 0x73,
+ 0x96, 0x50, 0xe1, 0xb0, 0xaf, 0x49, 0x39, 0xb4, 0xf0, 0x3a, 0x78, 0x38,
+ 0x70, 0xa9, 0x91, 0x5d, 0x5e, 0x07, 0xf4, 0xec, 0xbb, 0xc4, 0xe5, 0x8a,
+ 0xb8, 0x06, 0xba, 0xdf, 0xc6, 0x48, 0x78, 0x4b, 0xca, 0x2a, 0x8a, 0x92,
+ 0x64, 0xe3, 0xa6, 0xae, 0x87, 0x97, 0x12, 0x16, 0x46, 0x67, 0x59, 0xdf,
+ 0xf2, 0xf3, 0x89, 0x6f, 0xe8, 0xa9, 0x13, 0x57, 0x63, 0x4e, 0x07, 0x98,
+ 0xcc, 0x73, 0xa0, 0x84, 0x9d, 0xe8, 0xb3, 0x50, 0x59, 0xb5, 0x51, 0xb3,
+ 0x41, 0x7d, 0x55, 0xfe, 0xd9, 0xf0, 0xc6, 0xff, 0x6e, 0x96, 0x4f, 0x22,
+ 0xb2, 0x0d, 0x6b, 0xc9, 0x83, 0x2d, 0x98, 0x98, 0xb2, 0xd1, 0xb7, 0xe4,
+ 0x50, 0x83, 0x1a, 0xa9, 0x02, 0x9f, 0xaf, 0x54, 0x74, 0x2a, 0x2c, 0x63,
+ 0x10, 0x79, 0x45, 0x5c, 0x95, 0x0d, 0xa1, 0x9b, 0x55, 0xf3, 0x1e, 0xb7,
+ 0x56, 0x59, 0xf1, 0x59, 0x8d, 0xd6, 0x15, 0x89, 0xf6, 0xfe, 0xc0, 0x00,
+ 0xdd, 0x1f, 0x2b, 0xf0, 0xf7, 0x5d, 0x64, 0x84, 0x76, 0xd3, 0xc2, 0x92,
+ 0x35, 0xac, 0xb5, 0xf9, 0xf6, 0xa8, 0x05, 0x89, 0x4c, 0x95, 0x41, 0x4e,
+ 0x34, 0x25, 0x11, 0x14,
+};
+
+// kEstonianRSAKey is an RSAPublicKey encoded with a negative modulus. See
+// https://crbug.com/532048.
+static const uint8_t kEstonianRSAKey[] = {
+ 0x30, 0x82, 0x01, 0x09, 0x02, 0x82, 0x01, 0x00, 0x96, 0xa6, 0x2e, 0x9c,
+ 0x4e, 0x6a, 0xc3, 0xcc, 0xcd, 0x8f, 0x70, 0xc3, 0x55, 0xbf, 0x5e, 0x9c,
+ 0xd4, 0xf3, 0x17, 0xc3, 0x97, 0x70, 0xae, 0xdf, 0x12, 0x5c, 0x15, 0x80,
+ 0x03, 0xef, 0x2b, 0x18, 0x9d, 0x6a, 0xcb, 0x52, 0x22, 0xc1, 0x81, 0xb8,
+ 0x7e, 0x61, 0xe8, 0x0f, 0x79, 0x24, 0x0f, 0x82, 0x70, 0x24, 0x4e, 0x29,
+ 0x20, 0x05, 0x54, 0xeb, 0xd4, 0xa9, 0x65, 0x59, 0xb6, 0x3c, 0x75, 0x95,
+ 0x2f, 0x4c, 0xf6, 0x9d, 0xd1, 0xaf, 0x5f, 0x14, 0x14, 0xe7, 0x25, 0xea,
+ 0xa5, 0x47, 0x5d, 0xc6, 0x3e, 0x28, 0x8d, 0xdc, 0x54, 0x87, 0x2a, 0x7c,
+ 0x10, 0xe9, 0xc6, 0x76, 0x2d, 0xe7, 0x79, 0xd8, 0x0e, 0xbb, 0xa9, 0xac,
+ 0xb5, 0x18, 0x98, 0xd6, 0x47, 0x6e, 0x06, 0x70, 0xbf, 0x9e, 0x82, 0x25,
+ 0x95, 0x4e, 0xfd, 0x70, 0xd7, 0x73, 0x45, 0x2e, 0xc1, 0x1f, 0x7a, 0x9a,
+ 0x9d, 0x60, 0xc0, 0x1f, 0x67, 0x06, 0x2a, 0x4e, 0x87, 0x3f, 0x19, 0x88,
+ 0x69, 0x64, 0x4d, 0x9f, 0x75, 0xf5, 0xd3, 0x1a, 0x41, 0x3d, 0x35, 0x17,
+ 0xb6, 0xd1, 0x44, 0x0d, 0x25, 0x8b, 0xe7, 0x94, 0x39, 0xb0, 0x7c, 0xaf,
+ 0x3e, 0x6a, 0xfa, 0x8d, 0x90, 0x21, 0x0f, 0x8a, 0x43, 0x94, 0x37, 0x7c,
+ 0x2a, 0x15, 0x4c, 0xa0, 0xfa, 0xa9, 0x2f, 0x21, 0xa6, 0x6f, 0x8e, 0x2f,
+ 0x89, 0xbc, 0xbb, 0x33, 0xf8, 0x31, 0xfc, 0xdf, 0xcd, 0x68, 0x9a, 0xbc,
+ 0x75, 0x06, 0x95, 0xf1, 0x3d, 0xef, 0xca, 0x76, 0x27, 0xd2, 0xba, 0x8e,
+ 0x0e, 0x1c, 0x43, 0xd7, 0x70, 0xb9, 0xc6, 0x15, 0xca, 0xd5, 0x4d, 0x87,
+ 0xb9, 0xd1, 0xae, 0xde, 0x69, 0x73, 0x00, 0x2a, 0x97, 0x51, 0x4b, 0x30,
+ 0x01, 0xc2, 0x85, 0xd0, 0x05, 0xcc, 0x2e, 0xe8, 0xc7, 0x42, 0xe7, 0x94,
+ 0x51, 0xe3, 0xf5, 0x19, 0x35, 0xdc, 0x57, 0x96, 0xe7, 0xd9, 0xb4, 0x49,
+ 0x02, 0x03, 0x01, 0x00, 0x01,
+};
+
+static bool TestRSA(const uint8_t *der, size_t der_len,
+ const uint8_t *oaep_ciphertext,
+ size_t oaep_ciphertext_len) {
+ ScopedRSA key(d2i_RSAPrivateKey(nullptr, &der, der_len));
+ if (!key) {
+ return false;
+ }
+
+ if (!RSA_check_key(key.get())) {
+ fprintf(stderr, "RSA_check_key failed\n");
+ return false;
+ }
+
+ uint8_t ciphertext[256];
+
+ int num = RSA_public_encrypt(kPlaintextLen, kPlaintext, ciphertext, key.get(),
+ RSA_PKCS1_PADDING);
+ if (num < 0 || (size_t)num != RSA_size(key.get())) {
+ fprintf(stderr, "PKCS#1 v1.5 encryption failed!\n");
+ return false;
+ }
+
+ uint8_t plaintext[256];
+ num = RSA_private_decrypt(num, ciphertext, plaintext, key.get(),
+ RSA_PKCS1_PADDING);
+ if (num < 0 ||
+ (size_t)num != kPlaintextLen || memcmp(plaintext, kPlaintext, num) != 0) {
+ fprintf(stderr, "PKCS#1 v1.5 decryption failed!\n");
+ return false;
+ }
+
+ num = RSA_public_encrypt(kPlaintextLen, kPlaintext, ciphertext, key.get(),
+ RSA_PKCS1_OAEP_PADDING);
+ if (num < 0 || (size_t)num != RSA_size(key.get())) {
+ fprintf(stderr, "OAEP encryption failed!\n");
+ return false;
+ }
+
+ num = RSA_private_decrypt(num, ciphertext, plaintext, key.get(),
+ RSA_PKCS1_OAEP_PADDING);
+ if (num < 0 ||
+ (size_t)num != kPlaintextLen || memcmp(plaintext, kPlaintext, num) != 0) {
+ fprintf(stderr, "OAEP decryption (encrypted data) failed!\n");
+ return false;
+ }
+
+ // |oaep_ciphertext| should decrypt to |kPlaintext|.
+ num = RSA_private_decrypt(oaep_ciphertext_len, oaep_ciphertext, plaintext,
+ key.get(), RSA_PKCS1_OAEP_PADDING);
+
+ if (num < 0 ||
+ (size_t)num != kPlaintextLen || memcmp(plaintext, kPlaintext, num) != 0) {
+ fprintf(stderr, "OAEP decryption (test vector data) failed!\n");
+ return false;
+ }
+
+ // Try decrypting corrupted ciphertexts.
+ memcpy(ciphertext, oaep_ciphertext, oaep_ciphertext_len);
+ for (size_t i = 0; i < oaep_ciphertext_len; i++) {
+ uint8_t saved = ciphertext[i];
+ for (unsigned b = 0; b < 256; b++) {
+ if (b == saved) {
+ continue;
+ }
+ ciphertext[i] = b;
+ num = RSA_private_decrypt(num, ciphertext, plaintext, key.get(),
+ RSA_PKCS1_OAEP_PADDING);
+ if (num > 0) {
+ fprintf(stderr, "Corrupt data decrypted!\n");
+ return false;
+ }
+ }
+ ciphertext[i] = saved;
+ }
+
+ return true;
+}
+
+static bool TestMultiPrimeKey(int nprimes, const uint8_t *der, size_t der_size,
+ const uint8_t *enc, size_t enc_size) {
+ ScopedRSA rsa(d2i_RSAPrivateKey(nullptr, &der, der_size));
+ if (!rsa) {
+ fprintf(stderr, "%d-prime key failed to parse.\n", nprimes);
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ if (!RSA_check_key(rsa.get())) {
+ fprintf(stderr, "RSA_check_key failed for %d-prime key.\n", nprimes);
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ uint8_t out[256];
+ size_t out_len;
+ if (!RSA_decrypt(rsa.get(), &out_len, out, sizeof(out), enc, enc_size,
+ RSA_PKCS1_PADDING) ||
+ out_len != 11 ||
+ memcmp(out, "hello world", 11) != 0) {
+ fprintf(stderr, "%d-prime key failed to decrypt.\n", nprimes);
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestMultiPrimeKeygen() {
+ static const char kMessage[] = "Hello world.";
+ static const size_t kBits = 1024;
+ uint8_t encrypted[kBits / 8], decrypted[kBits / 8];
+ size_t encrypted_len, decrypted_len;
+
+ ScopedRSA rsa(RSA_new());
+ ScopedBIGNUM e(BN_new());
+ if (!rsa || !e ||
+ !BN_set_word(e.get(), RSA_F4) ||
+ !RSA_generate_multi_prime_key(rsa.get(), kBits, 3, e.get(), nullptr) ||
+ !RSA_check_key(rsa.get()) ||
+ !RSA_encrypt(rsa.get(), &encrypted_len, encrypted, sizeof(encrypted),
+ (const uint8_t *)kMessage, sizeof(kMessage),
+ RSA_PKCS1_PADDING) ||
+ !RSA_decrypt(rsa.get(), &decrypted_len, decrypted, sizeof(decrypted),
+ encrypted, encrypted_len, RSA_PKCS1_PADDING) ||
+ decrypted_len != sizeof(kMessage) ||
+ memcmp(decrypted, kMessage, sizeof(kMessage)) != 0) {
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestBadKey() {
+ ScopedRSA key(RSA_new());
+ ScopedBIGNUM e(BN_new());
+
+ if (!key || !e || !BN_set_word(e.get(), RSA_F4)) {
+ return false;
+ }
+
+ if (!RSA_generate_key_ex(key.get(), 512, e.get(), nullptr)) {
+ fprintf(stderr, "RSA_generate_key_ex failed.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ if (!BN_add(key->p, key->p, BN_value_one())) {
+ fprintf(stderr, "BN error.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ if (RSA_check_key(key.get())) {
+ fprintf(stderr, "RSA_check_key passed with invalid key!\n");
+ return false;
+ }
+
+ ERR_clear_error();
+ return true;
+}
+
+static bool TestOnlyDGiven() {
+ uint8_t buf[64];
+ unsigned buf_len = sizeof(buf);
+ ScopedRSA key(RSA_new());
+ if (!key ||
+ !BN_hex2bn(&key->n,
+ "00e77bbf3889d4ef36a9a25d4d69f3f632eb4362214c74517da6d6aeaa9bd"
+ "09ac42b26621cd88f3a6eb013772fc3bf9f83914b6467231c630202c35b3e"
+ "5808c659") ||
+ !BN_hex2bn(&key->e, "010001") ||
+ !BN_hex2bn(&key->d,
+ "0365db9eb6d73b53b015c40cd8db4de7dd7035c68b5ac1bf786d7a4ee2cea"
+ "316eaeca21a73ac365e58713195f2ae9849348525ca855386b6d028e437a9"
+ "495a01") ||
+ RSA_size(key.get()) > sizeof(buf)) {
+ return false;
+ }
+
+ if (!RSA_check_key(key.get())) {
+ fprintf(stderr, "RSA_check_key failed with only d given.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ const uint8_t kDummyHash[16] = {0};
+
+ if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
+ key.get())) {
+ fprintf(stderr, "RSA_sign failed with only d given.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
+ key.get())) {
+ fprintf(stderr, "RSA_verify failed with only d given.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ return true;
+}
+
+static bool TestRecoverCRTParams() {
+ ScopedBIGNUM e(BN_new());
+ if (!e || !BN_set_word(e.get(), RSA_F4)) {
+ return false;
+ }
+
+ ERR_clear_error();
+
+ for (unsigned i = 0; i < 1; i++) {
+ ScopedRSA key1(RSA_new());
+ if (!key1 ||
+ !RSA_generate_key_ex(key1.get(), 512, e.get(), nullptr)) {
+ fprintf(stderr, "RSA_generate_key_ex failed.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ if (!RSA_check_key(key1.get())) {
+ fprintf(stderr, "RSA_check_key failed with original key.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ ScopedRSA key2(RSA_new());
+ if (!key2) {
+ return false;
+ }
+ key2->n = BN_dup(key1->n);
+ key2->e = BN_dup(key1->e);
+ key2->d = BN_dup(key1->d);
+ if (key2->n == nullptr || key2->e == nullptr || key2->d == nullptr) {
+ return false;
+ }
+
+ if (!RSA_recover_crt_params(key2.get())) {
+ fprintf(stderr, "RSA_recover_crt_params failed.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ uint8_t buf[128];
+ unsigned buf_len = sizeof(buf);
+ if (RSA_size(key2.get()) > buf_len) {
+ return false;
+ }
+
+ if (!RSA_check_key(key2.get())) {
+ fprintf(stderr, "RSA_check_key failed with recovered key.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ const uint8_t kDummyHash[16] = {0};
+ if (!RSA_sign(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, &buf_len,
+ key2.get())) {
+ fprintf(stderr, "RSA_sign failed with recovered key.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+
+ if (!RSA_verify(NID_sha256, kDummyHash, sizeof(kDummyHash), buf, buf_len,
+ key2.get())) {
+ fprintf(stderr, "RSA_verify failed with recovered key.\n");
+ ERR_print_errors_fp(stderr);
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool TestASN1() {
+ // Test that private keys may be decoded.
+ ScopedRSA rsa(RSA_private_key_from_bytes(kKey1, sizeof(kKey1) - 1));
+ if (!rsa) {
+ return false;
+ }
+
+ // Test that the serialization round-trips.
+ uint8_t *der;
+ size_t der_len;
+ if (!RSA_private_key_to_bytes(&der, &der_len, rsa.get())) {
+ return false;
+ }
+ ScopedOpenSSLBytes delete_der(der);
+ if (der_len != sizeof(kKey1) - 1 || memcmp(der, kKey1, der_len) != 0) {
+ return false;
+ }
+
+ // Test that serializing public keys works.
+ if (!RSA_public_key_to_bytes(&der, &der_len, rsa.get())) {
+ return false;
+ }
+ delete_der.reset(der);
+
+ // Public keys may be parsed back out.
+ rsa.reset(RSA_public_key_from_bytes(der, der_len));
+ if (!rsa || rsa->p != NULL || rsa->q != NULL) {
+ return false;
+ }
+
+ // Serializing the result round-trips.
+ uint8_t *der2;
+ size_t der2_len;
+ if (!RSA_public_key_to_bytes(&der2, &der2_len, rsa.get())) {
+ return false;
+ }
+ ScopedOpenSSLBytes delete_der2(der2);
+ if (der_len != der2_len || memcmp(der, der2, der_len) != 0) {
+ return false;
+ }
+
+ // Public keys cannot be serialized as private keys.
+ if (RSA_private_key_to_bytes(&der, &der_len, rsa.get())) {
+ OPENSSL_free(der);
+ return false;
+ }
+ ERR_clear_error();
+
+ // Public keys with negative moduli are invalid.
+ rsa.reset(RSA_public_key_from_bytes(kEstonianRSAKey,
+ sizeof(kEstonianRSAKey)));
+ if (rsa) {
+ return false;
+ }
+ ERR_clear_error();
+
+ // But |RSA_parse_public_key_buggy| will accept it.
+ CBS cbs;
+ CBS_init(&cbs, kEstonianRSAKey, sizeof(kEstonianRSAKey));
+ rsa.reset(RSA_parse_public_key_buggy(&cbs));
+ if (!rsa || CBS_len(&cbs) != 0) {
+ return false;
+ }
+
+ return true;
+}
+
+int main(int argc, char *argv[]) {
+ CRYPTO_library_init();
+
+ if (!TestRSA(kKey1, sizeof(kKey1) - 1, kOAEPCiphertext1,
+ sizeof(kOAEPCiphertext1) - 1) ||
+ !TestRSA(kKey2, sizeof(kKey2) - 1, kOAEPCiphertext2,
+ sizeof(kOAEPCiphertext2) - 1) ||
+ !TestRSA(kKey3, sizeof(kKey3) - 1, kOAEPCiphertext3,
+ sizeof(kOAEPCiphertext3) - 1) ||
+ !TestOnlyDGiven() ||
+ !TestRecoverCRTParams() ||
+ !TestBadKey() ||
+ !TestMultiPrimeKey(2, kTwoPrimeKey, sizeof(kTwoPrimeKey) - 1,
+ kTwoPrimeEncryptedMessage,
+ sizeof(kTwoPrimeEncryptedMessage)) ||
+ !TestMultiPrimeKey(3, kThreePrimeKey, sizeof(kThreePrimeKey) - 1,
+ kThreePrimeEncryptedMessage,
+ sizeof(kThreePrimeEncryptedMessage)) ||
+ !TestMultiPrimeKey(6, kSixPrimeKey, sizeof(kSixPrimeKey) - 1,
+ kSixPrimeEncryptedMessage,
+ sizeof(kSixPrimeEncryptedMessage)) ||
+ !TestMultiPrimeKeygen() ||
+ !TestASN1()) {
+ return 1;
+ }
+
+ printf("PASS\n");
+ return 0;
+}