chore: checkpoint before Python removal

This commit is contained in:
2026-03-26 22:33:59 +00:00
parent 683cec9307
commit e568ddf82a
29972 changed files with 11269302 additions and 2 deletions

View File

@@ -0,0 +1,96 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/base.h>
#include <openssl/bytestring.h>
#if defined(__cplusplus)
extern "C" {
#endif
#define PSS_DEFAULT_SALT_LEN 20
#define PSS_TRAILER_FIELD_VALUE 1
// Section 2.1. https://tools.ietf.org/html/rfc4055#section-2.1
typedef struct rsa_pss_supported_algor_st {
int nid;
uint8_t oid[9];
uint8_t oid_len;
} RSA_PSS_SUPPORTED_ALGOR;
typedef struct rsa_algor_identifier_st {
int nid;
} RSA_ALGOR_IDENTIFIER;
typedef struct rsa_mga_identifier_st {
// Mask generation algorithm identifier.
RSA_ALGOR_IDENTIFIER *mask_gen;
// Associated hash algorithm identifier.
RSA_ALGOR_IDENTIFIER *one_way_hash;
} RSA_MGA_IDENTIFIER;
typedef struct rsa_integer_st {
int64_t value;
} RSA_INTEGER;
// RSASSA-PSS-params is defined on rfc4055 section 3.1.
// See https://tools.ietf.org/html/rfc4055#section-3.1
struct rsassa_pss_params_st {
RSA_ALGOR_IDENTIFIER *hash_algor;
RSA_MGA_IDENTIFIER *mask_gen_algor;
RSA_INTEGER *salt_len;
RSA_INTEGER *trailer_field;
};
// RSASSA_PSS_PARAMS related malloc functions.
RSA_INTEGER *RSA_INTEGER_new(void);
RSA_ALGOR_IDENTIFIER *RSA_ALGOR_IDENTIFIER_new(void);
RSA_MGA_IDENTIFIER *RSA_MGA_IDENTIFIER_new(void);
OPENSSL_EXPORT RSASSA_PSS_PARAMS *RSASSA_PSS_PARAMS_new(void);
// RSASSA_PSS_PARAMS related free functions.
void RSA_INTEGER_free(RSA_INTEGER *ptr);
void RSA_ALGOR_IDENTIFIER_free(RSA_ALGOR_IDENTIFIER *ptr);
void RSA_MGA_IDENTIFIER_free(RSA_MGA_IDENTIFIER *identifier);
OPENSSL_EXPORT void RSASSA_PSS_PARAMS_free(RSASSA_PSS_PARAMS *params);
// RSASSA_PSS_parse_params return one on success and zero on failure.
// If success and the |params| are not empty, |*pss| will be allocated
// and have the bytes parsed. Otherwise, |*pss| will be NULL.
OPENSSL_EXPORT int RSASSA_PSS_parse_params(CBS *params,
RSASSA_PSS_PARAMS **pss);
// RSASSA_PSS_PARAMS_create return one on success and zero on failure.
// When success and the given algorithms are not default (sha1),
// |*out| will hold the allocated |RSASSA_PSS_PARAMS|.
OPENSSL_EXPORT int RSASSA_PSS_PARAMS_create(const EVP_MD *sigmd,
const EVP_MD *mgf1md, int saltlen,
RSASSA_PSS_PARAMS **out);
// RSASSA_PSS_PARAMS_get return one on success and zero on failure.
// When success, |*md|, |*mgf1md| and |saltlen| will get assigned.
OPENSSL_EXPORT int RSASSA_PSS_PARAMS_get(const RSASSA_PSS_PARAMS *pss,
const EVP_MD **md,
const EVP_MD **mgf1md, int *saltlen);
int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *out, size_t *out_len,
size_t max_out, const uint8_t *from,
size_t from_len, const uint8_t *param,
size_t param_len, const EVP_MD *md,
const EVP_MD *mgf1md);
#if defined(__cplusplus)
} // extern C
extern "C++" {
BSSL_NAMESPACE_BEGIN
BORINGSSL_MAKE_DELETER(RSASSA_PSS_PARAMS, RSASSA_PSS_PARAMS_free)
BSSL_NAMESPACE_END
} // extern C++
#endif

View File

@@ -0,0 +1,300 @@
// Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL project 2000.
// Copyright (c) 2000-2005 The OpenSSL Project. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/rsa.h>
#include <assert.h>
#include <limits.h>
#include <string.h>
#include <openssl/bn.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../fipsmodule/rsa/internal.h"
#include "../bytestring/internal.h"
#include "../internal.h"
static int parse_integer(CBS *cbs, BIGNUM **out) {
assert(*out == NULL);
*out = BN_new();
if (*out == NULL) {
return 0;
}
return BN_parse_asn1_unsigned(cbs, *out);
}
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_marshal_asn1(cbb, bn);
}
RSA *RSA_parse_public_key(CBS *cbs) {
RSA *ret = RSA_new();
if (ret == NULL) {
return NULL;
}
CBS child;
if (!CBS_get_asn1(cbs, &child, CBS_ASN1_SEQUENCE) ||
!parse_integer(&child, &ret->n) ||
!parse_integer(&child, &ret->e) ||
CBS_len(&child) != 0) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
RSA_free(ret);
return NULL;
}
if (!RSA_check_key(ret)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_RSA_PARAMETERS);
RSA_free(ret);
return NULL;
}
return ret;
}
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 is the value of the version field for a two-prime
// RSAPrivateKey structure (RFC 8017).
static const uint64_t kVersionTwoPrime = 0;
// Distinguisher for stripped JCA RSA private keys, sets zeroed values to NULL
// because ASN.1 treats absent values as 0, but post-parsing validation logic
// expects absent values to be NULL. Returns 1 if JCA stripped private key, 0
// otherwise.
static void detect_stripped_jca_private_key(RSA *key) {
if (!BN_is_zero(key->d) && !BN_is_zero(key->n) &&
BN_is_zero(key->e) && BN_is_zero(key->iqmp) &&
BN_is_zero(key->p) && BN_is_zero(key->q) &&
BN_is_zero(key->dmp1) && BN_is_zero(key->dmq1)) {
BN_free(key->e);
BN_free(key->p);
BN_free(key->q);
BN_free(key->dmp1);
BN_free(key->dmq1);
BN_free(key->iqmp);
key->e = NULL;
key->p = NULL;
key->q = NULL;
key->dmp1 = NULL;
key->dmq1 = NULL;
key->iqmp = NULL;
key->flags |= RSA_FLAG_NO_PUBLIC_EXPONENT;
}
}
RSA *RSA_parse_private_key(CBS *cbs) {
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)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
goto err;
}
if (version != kVersionTwoPrime) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_VERSION);
goto err;
}
if (!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)) {
goto err;
}
if (CBS_len(&child) != 0) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_ENCODING);
goto err;
}
detect_stripped_jca_private_key(ret);
if (!RSA_check_key(ret)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_BAD_RSA_PARAMETERS);
goto err;
}
return ret;
err:
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) {
CBB child;
if (!CBB_add_asn1(cbb, &child, CBS_ASN1_SEQUENCE) ||
!CBB_add_asn1_uint64(&child, 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) ||
!CBB_flush(cbb)) {
OPENSSL_PUT_ERROR(RSA, RSA_R_ENCODE_ERROR);
return 0;
}
return 1;
}
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;
}
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 = CBS_data(&cbs);
return ret;
}
int i2d_RSAPublicKey(const RSA *in, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!RSA_marshal_public_key(&cbb, in)) {
CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
}
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 = CBS_data(&cbs);
return ret;
}
int i2d_RSAPrivateKey(const RSA *in, uint8_t **outp) {
CBB cbb;
if (!CBB_init(&cbb, 0) ||
!RSA_marshal_private_key(&cbb, in)) {
CBB_cleanup(&cbb);
return -1;
}
return CBB_finish_i2d(&cbb, outp);
}
RSA *RSAPublicKey_dup(const 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) {
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;
}

View File

@@ -0,0 +1,561 @@
// Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) All rights reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/base.h>
#include <limits.h>
#include <openssl/err.h>
#include <openssl/rsa.h>
#include <openssl/bn.h>
#include <openssl/rand.h>
#include <openssl/mem.h>
#include <openssl/evp.h>
#include "../fipsmodule/bn/internal.h"
#include "../fipsmodule/rsa/internal.h"
#include "../internal.h"
#include "internal.h"
static void rand_nonzero(uint8_t *out, size_t len) {
AWSLC_ABORT_IF_NOT_ONE(RAND_bytes(out, len));
for (size_t i = 0; i < len; i++) {
// Zero values are replaced, and the distribution of zero and non-zero bytes
// is public, so leaking this is safe.
while (constant_time_declassify_int(out[i] == 0)) {
AWSLC_ABORT_IF_NOT_ONE(RAND_bytes(out + i, 1));
}
}
}
int RSA_padding_add_PKCS1_OAEP_mgf1(uint8_t *to, size_t to_len,
const uint8_t *from, size_t from_len,
const uint8_t *param, size_t param_len,
const EVP_MD *md, const EVP_MD *mgf1md) {
if (md == NULL) {
md = EVP_sha1();
}
if (mgf1md == NULL) {
mgf1md = md;
}
size_t mdlen = EVP_MD_size(md);
if (to_len < 2 * mdlen + 2) {
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
size_t emlen = to_len - 1;
if (from_len > emlen - 2 * mdlen - 1) {
OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
}
if (emlen < 2 * mdlen + 1) {
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
to[0] = 0;
uint8_t *seed = to + 1;
uint8_t *db = to + mdlen + 1;
uint8_t *dbmask = NULL;
int ret = 0;
if (!EVP_Digest(param, param_len, db, NULL, md, NULL)) {
goto out;
}
OPENSSL_memset(db + mdlen, 0, emlen - from_len - 2 * mdlen - 1);
db[emlen - from_len - mdlen - 1] = 0x01;
OPENSSL_memcpy(db + emlen - from_len - mdlen, from, from_len);
AWSLC_ABORT_IF_NOT_ONE(RAND_bytes(seed, mdlen));
dbmask = OPENSSL_malloc(emlen - mdlen);
if (dbmask == NULL) {
goto out;
}
OPENSSL_BEGIN_ALLOW_DEPRECATED
if (!PKCS1_MGF1(dbmask, emlen - mdlen, seed, mdlen, mgf1md)) {
goto out;
}
for (size_t i = 0; i < emlen - mdlen; i++) {
db[i] ^= dbmask[i];
}
uint8_t seedmask[EVP_MAX_MD_SIZE];
if (!PKCS1_MGF1(seedmask, mdlen, db, emlen - mdlen, mgf1md)) {
goto out;
}
OPENSSL_END_ALLOW_DEPRECATED
for (size_t i = 0; i < mdlen; i++) {
seed[i] ^= seedmask[i];
}
ret = 1;
out:
OPENSSL_free(dbmask);
return ret;
}
int RSA_padding_check_PKCS1_OAEP_mgf1(uint8_t *out, size_t *out_len,
size_t max_out, const uint8_t *from,
size_t from_len, const uint8_t *param,
size_t param_len, const EVP_MD *md,
const EVP_MD *mgf1md) {
uint8_t *db = NULL;
if (md == NULL) {
md = EVP_sha1();
}
if (mgf1md == NULL) {
mgf1md = md;
}
size_t mdlen = EVP_MD_size(md);
// The encoded message is one byte smaller than the modulus to ensure that it
// doesn't end up greater than the modulus. Thus there's an extra "+1" here
// compared to https://tools.ietf.org/html/rfc2437#section-9.1.1.2.
if (from_len < 1 + 2 * mdlen + 1) {
// 'from_len' is the length of the modulus, i.e. does not depend on the
// particular ciphertext.
goto decoding_err;
}
size_t dblen = from_len - mdlen - 1;
db = OPENSSL_malloc(dblen);
if (db == NULL) {
goto err;
}
const uint8_t *maskedseed = from + 1;
const uint8_t *maskeddb = from + 1 + mdlen;
uint8_t seed[EVP_MAX_MD_SIZE];
OPENSSL_BEGIN_ALLOW_DEPRECATED
if (!PKCS1_MGF1(seed, mdlen, maskeddb, dblen, mgf1md)) {
goto err;
}
for (size_t i = 0; i < mdlen; i++) {
seed[i] ^= maskedseed[i];
}
if (!PKCS1_MGF1(db, dblen, seed, mdlen, mgf1md)) {
goto err;
}
OPENSSL_END_ALLOW_DEPRECATED
for (size_t i = 0; i < dblen; i++) {
db[i] ^= maskeddb[i];
}
uint8_t phash[EVP_MAX_MD_SIZE];
if (!EVP_Digest(param, param_len, phash, NULL, md, NULL)) {
goto err;
}
crypto_word_t bad = ~constant_time_is_zero_w(CRYPTO_memcmp(db, phash, mdlen));
bad |= ~constant_time_is_zero_w(from[0]);
crypto_word_t looking_for_one_byte = CONSTTIME_TRUE_W;
size_t one_index = 0;
for (size_t i = mdlen; i < dblen; i++) {
crypto_word_t equals1 = constant_time_eq_w(db[i], 1);
crypto_word_t equals0 = constant_time_eq_w(db[i], 0);
one_index =
constant_time_select_w(looking_for_one_byte & equals1, i, one_index);
looking_for_one_byte =
constant_time_select_w(equals1, 0, looking_for_one_byte);
bad |= looking_for_one_byte & ~equals0;
}
bad |= looking_for_one_byte;
// Whether the overall padding was valid or not in OAEP is public.
if (constant_time_declassify_w(bad)) {
goto decoding_err;
}
// Once the padding is known to be valid, the output length is also public.
OPENSSL_STATIC_ASSERT(sizeof(size_t) <= sizeof(crypto_word_t),
size_t_does_not_fit_in_crypto_word_t);
one_index = constant_time_declassify_w(one_index);
one_index++;
size_t mlen = dblen - one_index;
if (max_out < mlen) {
OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE);
goto err;
}
OPENSSL_memcpy(out, db + one_index, mlen);
*out_len = mlen;
OPENSSL_free(db);
return 1;
decoding_err:
// To avoid chosen ciphertext attacks, the error message should not reveal
// which kind of decoding error happened.
OPENSSL_PUT_ERROR(RSA, RSA_R_OAEP_DECODING_ERROR);
err:
OPENSSL_free(db);
return 0;
}
static int rsa_padding_add_PKCS1_type_2(uint8_t *to, size_t to_len,
const uint8_t *from, size_t from_len) {
// See RFC 8017, section 7.2.1.
if (to_len < RSA_PKCS1_PADDING_SIZE) {
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
if (from_len > to_len - RSA_PKCS1_PADDING_SIZE) {
OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_KEY_SIZE);
return 0;
}
to[0] = 0;
to[1] = 2;
size_t padding_len = to_len - 3 - from_len;
rand_nonzero(to + 2, padding_len);
to[2 + padding_len] = 0;
OPENSSL_memcpy(to + to_len - from_len, from, from_len);
return 1;
}
static int rsa_padding_check_PKCS1_type_2(uint8_t *out, size_t *out_len,
size_t max_out, const uint8_t *from,
size_t from_len) {
if (from_len == 0) {
OPENSSL_PUT_ERROR(RSA, RSA_R_EMPTY_PUBLIC_KEY);
return 0;
}
// PKCS#1 v1.5 decryption. See "PKCS #1 v2.2: RSA Cryptography
// Standard", section 7.2.2.
if (from_len < RSA_PKCS1_PADDING_SIZE) {
// |from| is zero-padded to the size of the RSA modulus, a public value, so
// this can be rejected in non-constant time.
OPENSSL_PUT_ERROR(RSA, RSA_R_KEY_SIZE_TOO_SMALL);
return 0;
}
crypto_word_t first_byte_is_zero = constant_time_eq_w(from[0], 0);
crypto_word_t second_byte_is_two = constant_time_eq_w(from[1], 2);
crypto_word_t zero_index = 0, looking_for_index = CONSTTIME_TRUE_W;
for (size_t i = 2; i < from_len; i++) {
crypto_word_t equals0 = constant_time_is_zero_w(from[i]);
zero_index =
constant_time_select_w(looking_for_index & equals0, i, zero_index);
looking_for_index = constant_time_select_w(equals0, 0, looking_for_index);
}
// The input must begin with 00 02.
crypto_word_t valid_index = first_byte_is_zero;
valid_index &= second_byte_is_two;
// We must have found the end of PS.
valid_index &= ~looking_for_index;
// PS must be at least 8 bytes long, and it starts two bytes into |from|.
valid_index &= constant_time_ge_w(zero_index, 2 + 8);
// Skip the zero byte.
zero_index++;
// NOTE: Although this logic attempts to be constant time, the API contracts
// of this function and |RSA_decrypt| with |RSA_PKCS1_PADDING| make it
// impossible to completely avoid Bleichenbacher's attack. Consumers should
// use |RSA_PADDING_NONE| and perform the padding check in constant-time
// combined with a swap to a random session key or other mitigation.
CONSTTIME_DECLASSIFY(&valid_index, sizeof(valid_index));
CONSTTIME_DECLASSIFY(&zero_index, sizeof(zero_index));
if (!valid_index) {
OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR);
return 0;
}
const size_t msg_len = from_len - zero_index;
if (msg_len > max_out) {
// This shouldn't happen because this function is always called with
// |max_out| as the key size and |from_len| is bounded by the key size.
OPENSSL_PUT_ERROR(RSA, RSA_R_PKCS_DECODING_ERROR);
return 0;
}
OPENSSL_memcpy(out, &from[zero_index], msg_len);
*out_len = msg_len;
return 1;
}
int RSA_public_encrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
int padding) {
size_t out_len;
if (!RSA_encrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
return -1;
}
if (out_len > INT_MAX) {
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
return -1;
}
return (int)out_len;
}
int RSA_private_encrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
int padding) {
size_t out_len;
if (!RSA_sign_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
return -1;
}
if (out_len > INT_MAX) {
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
return -1;
}
return (int)out_len;
}
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 && rsa->meth->encrypt) {
// In OpenSSL, the RSA_METHOD |encrypt| or |pub_enc| operation does not
// directly take and initialize an |out_len| parameter. Instead, it returns
// the number of bytes written to |out| or a negative number for error.
// Our wrapping functions like |RSA_encrypt| diverge from this paradigm and
// expect an |out_len| parameter. To remain compatible with this new
// paradigm and OpenSSL, we initialize |out_len| based on the return value
// here.
if (max_out > INT_MAX) {
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
*out_len = 0;
return 0;
}
int ret = rsa->meth->encrypt((int)max_out, in, out, rsa, padding);
if(ret < 0) {
*out_len = 0;
return 0;
}
*out_len = ret;
return 1;
}
if (rsa->n == NULL || rsa->e == NULL) {
OPENSSL_PUT_ERROR(RSA, RSA_R_VALUE_MISSING);
return 0;
}
if (!is_public_component_of_rsa_key_good(rsa)) {
return 0;
}
const unsigned rsa_size = RSA_size(rsa);
BIGNUM *f, *result;
uint8_t *buf = NULL;
BN_CTX *ctx = NULL;
int i, ret = 0;
if (max_out < rsa_size) {
OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
ctx = BN_CTX_new();
if (ctx == NULL) {
goto err;
}
BN_CTX_start(ctx);
f = BN_CTX_get(ctx);
result = BN_CTX_get(ctx);
buf = OPENSSL_malloc(rsa_size);
if (!f || !result || !buf) {
goto err;
}
switch (padding) {
case RSA_PKCS1_PADDING:
i = rsa_padding_add_PKCS1_type_2(buf, rsa_size, in, in_len);
break;
case RSA_PKCS1_OAEP_PADDING:
// Use the default parameters: SHA-1 for both hashes and no label.
i = RSA_padding_add_PKCS1_OAEP_mgf1(buf, rsa_size, in, in_len, NULL, 0,
NULL, NULL);
break;
case RSA_NO_PADDING:
i = RSA_padding_add_none(buf, rsa_size, in, in_len);
break;
default:
OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
if (i <= 0) {
goto err;
}
if (BN_bin2bn(buf, rsa_size, f) == NULL) {
goto err;
}
if (BN_ucmp(f, rsa->n) >= 0) {
// usually the padding functions would catch this
OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_TOO_LARGE_FOR_MODULUS);
goto err;
}
if (!BN_MONT_CTX_set_locked(&rsa->mont_n, &rsa->lock, rsa->n, ctx) ||
!BN_mod_exp_mont(result, f, rsa->e, &rsa->mont_n->N, ctx, rsa->mont_n)) {
goto err;
}
// 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, ERR_R_INTERNAL_ERROR);
goto err;
}
*out_len = rsa_size;
ret = 1;
err:
if (ctx != NULL) {
BN_CTX_end(ctx);
BN_CTX_free(ctx);
}
OPENSSL_free(buf);
return ret;
}
static int rsa_default_decrypt(RSA *rsa, size_t *out_len, uint8_t *out,
size_t max_out, const uint8_t *in, size_t in_len,
int padding) {
const unsigned rsa_size = RSA_size(rsa);
uint8_t *buf = NULL;
int ret = 0;
if (max_out < rsa_size) {
OPENSSL_PUT_ERROR(RSA, RSA_R_OUTPUT_BUFFER_TOO_SMALL);
return 0;
}
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) {
goto err;
}
}
if (in_len != rsa_size) {
OPENSSL_PUT_ERROR(RSA, RSA_R_DATA_LEN_NOT_EQUAL_TO_MOD_LEN);
goto err;
}
if (!rsa_private_transform(rsa, buf, in, rsa_size)) {
goto err;
}
switch (padding) {
case RSA_PKCS1_PADDING:
ret =
rsa_padding_check_PKCS1_type_2(out, out_len, rsa_size, buf, rsa_size);
break;
case RSA_PKCS1_OAEP_PADDING:
// Use the default parameters: SHA-1 for both hashes and no label.
ret = RSA_padding_check_PKCS1_OAEP_mgf1(out, out_len, rsa_size, buf,
rsa_size, NULL, 0, NULL, NULL);
break;
case RSA_NO_PADDING:
*out_len = rsa_size;
ret = 1;
break;
default:
OPENSSL_PUT_ERROR(RSA, RSA_R_UNKNOWN_PADDING_TYPE);
goto err;
}
CONSTTIME_DECLASSIFY(&ret, sizeof(ret));
if (!ret) {
OPENSSL_PUT_ERROR(RSA, RSA_R_PADDING_CHECK_FAILED);
} else {
CONSTTIME_DECLASSIFY(out, *out_len);
}
err:
if (padding != RSA_NO_PADDING) {
OPENSSL_free(buf);
}
return ret;
}
int RSA_decrypt(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 && rsa->meth->decrypt) {
// In OpenSSL, the RSA_METHOD |decrypt| operation does not directly take
// and initialize an |out_len| parameter. Instead, it returns the number
// of bytes written to |out| or a negative number for error. Our wrapping
// functions like |RSA_decrypt| diverge from this paradigm and expect
// an |out_len| parameter. To remain compatible with this new paradigm and
// OpenSSL, we initialize |out_len| based on the return value here.
if (max_out > INT_MAX) {
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
*out_len = 0;
return 0;
}
int ret = rsa->meth->decrypt((int)max_out, in, out, rsa, padding);
if(ret < 0) {
*out_len = 0;
return 0;
}
*out_len = ret;
return 1;
}
return rsa_default_decrypt(rsa, out_len, out, max_out, in, in_len, padding);
}
int RSA_private_decrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
int padding) {
size_t out_len;
if (!RSA_decrypt(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
return -1;
}
if (out_len > INT_MAX) {
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
return -1;
}
return (int)out_len;
}
int RSA_public_decrypt(size_t flen, const uint8_t *from, uint8_t *to, RSA *rsa,
int padding) {
size_t out_len;
if (!RSA_verify_raw(rsa, &out_len, to, RSA_size(rsa), from, flen, padding)) {
return -1;
}
if (out_len > INT_MAX) {
OPENSSL_PUT_ERROR(RSA, ERR_R_OVERFLOW);
return -1;
}
return (int)out_len;
}

View File

@@ -0,0 +1,30 @@
// Copyright 2006-2017 The OpenSSL Project Authors. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#include <openssl/rsa.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#include <openssl/evp.h>
int RSA_print(BIO *bio, const RSA *rsa, int indent) {
EVP_PKEY *pkey = EVP_PKEY_new();
int ret = pkey != NULL &&
EVP_PKEY_set1_RSA(pkey, (RSA *)rsa) &&
EVP_PKEY_print_private(bio, pkey, indent, NULL);
EVP_PKEY_free(pkey);
return ret;
}
int RSA_print_fp(FILE *fp, const RSA *rsa, int indent) {
BIO *bio = BIO_new(BIO_s_file());
if (bio == NULL) {
OPENSSL_PUT_ERROR(RSA, ERR_R_BUF_LIB);
return 0;
}
BIO_set_fp(bio, fp, BIO_NOCLOSE);
int ret = RSA_print(bio, rsa, indent);
BIO_free(bio);
return ret;
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,504 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/evp.h>
#include <openssl/bytestring.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/mem.h>
#include "../internal.h"
#include "internal.h"
// Below macros are used with |get_context_specific_value|.
#define TAG_VALUE_INDEX_0 0
#define TAG_VALUE_INDEX_1 1
#define TAG_VALUE_INDEX_2 2
#define TAG_VALUE_INDEX_3 3
const RSA_PSS_SUPPORTED_ALGOR sha1_func = {
NID_sha1,
// 1.3.14.3.2.26
{0x2b, 0x0e, 0x03, 0x02, 0x1a},
5,
};
const RSA_PSS_SUPPORTED_ALGOR sha224_func = {
NID_sha224,
// 2.16.840.1.101.3.4.2.4
{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04},
9,
};
const RSA_PSS_SUPPORTED_ALGOR sha256_func = {
NID_sha256,
// 2.16.840.1.101.3.4.2.1
{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01},
9,
};
const RSA_PSS_SUPPORTED_ALGOR sha384_func = {
NID_sha384,
// 2.16.840.1.101.3.4.2.2
{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02},
9,
};
const RSA_PSS_SUPPORTED_ALGOR sha512_func = {
NID_sha512,
// 2.16.840.1.101.3.4.2.3
{0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03},
9,
};
// Used to check if the oid is in the supported five hash functions.
// Section 2.1. https://tools.ietf.org/html/rfc4055#page-4
static const RSA_PSS_SUPPORTED_ALGOR *const rsa_pss_hash_functions[] = {
&sha1_func, &sha224_func, &sha256_func, &sha384_func, &sha512_func,
};
const RSA_PSS_SUPPORTED_ALGOR MGF1 = {
NID_mgf1,
// 1.2.840.113549.1.1.8
{0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08},
9,
};
// Used to check if the oid is in the supported mask generation functions.
// Section 2.2. https://tools.ietf.org/html/rfc4055#section-2.2
static const RSA_PSS_SUPPORTED_ALGOR *const rsa_pss_mg_functions[] = {
&MGF1,
};
// parse_oid return one on success and zero on failure.
// Given |oid| and |supported_algors|, if match, set |*out| to be the algorithm
// identifier.
static int parse_oid(CBS *oid,
const RSA_PSS_SUPPORTED_ALGOR *const supported_algors[],
size_t size, RSA_ALGOR_IDENTIFIER **out) {
for (size_t i = 0; i < size; i++) {
const RSA_PSS_SUPPORTED_ALGOR *supported_algr = supported_algors[i];
if (CBS_len(oid) == supported_algr->oid_len &&
OPENSSL_memcmp(CBS_data(oid), supported_algr->oid,
supported_algr->oid_len) == 0) {
*out = RSA_ALGOR_IDENTIFIER_new();
if (*out == NULL) {
return 0;
}
(*out)->nid = supported_algr->nid;
return 1;
}
}
OPENSSL_PUT_ERROR(RSA, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
// For One-way Hash Functions:
// All implementations MUST accept both NULL and absent parameters as legal and
// equivalent encodings. See 2.1. https://tools.ietf.org/html/rfc4055#section-2.1
static int is_absent_or_null(CBS *params) {
CBS null;
return (CBS_len(params) == 0) ||
(CBS_get_asn1(params, &null, CBS_ASN1_NULL) && (CBS_len(&null) == 0) &&
(CBS_len(params) == 0));
}
// Decode One-way Hash Functions: return one on success and zero on failure.
// See 2.1. https://tools.ietf.org/html/rfc4055#page-5
static int decode_one_way_hash(CBS *cbs, RSA_ALGOR_IDENTIFIER **hash_algor) {
CBS seq, oid;
if (CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE) &&
(CBS_len(cbs) == 0) &&
CBS_get_asn1(&seq, &oid, CBS_ASN1_OBJECT) &&
is_absent_or_null(&seq) &&
parse_oid(&oid, rsa_pss_hash_functions,
OPENSSL_ARRAY_SIZE(rsa_pss_hash_functions), hash_algor)) {
return 1;
}
OPENSSL_PUT_ERROR(RSA, EVP_R_DECODE_ERROR);
return 0;
}
// Decode Mask Generation Functions: return one on success and zero on failure.
// See 2.2. https://tools.ietf.org/html/rfc4055#section-2.2
static int decode_mask_gen(CBS *cbs, RSA_MGA_IDENTIFIER **mga) {
CBS seq, mgf1_oid, hash_seq, hash_oid;
RSA_ALGOR_IDENTIFIER *mgf1 = NULL;
RSA_ALGOR_IDENTIFIER *hash_algor = NULL;
if (CBS_get_asn1(cbs, &seq, CBS_ASN1_SEQUENCE) &&
(CBS_len(cbs) == 0) &&
CBS_get_asn1(&seq, &mgf1_oid, CBS_ASN1_OBJECT) &&
parse_oid(&mgf1_oid, rsa_pss_mg_functions,
OPENSSL_ARRAY_SIZE(rsa_pss_mg_functions), &mgf1) &&
CBS_get_asn1(&seq, &hash_seq, CBS_ASN1_SEQUENCE) &&
(CBS_len(&seq) == 0) &&
CBS_get_asn1(&hash_seq, &hash_oid, CBS_ASN1_OBJECT) &&
is_absent_or_null(&hash_seq) &&
parse_oid(&hash_oid, rsa_pss_hash_functions,
OPENSSL_ARRAY_SIZE(rsa_pss_hash_functions), &hash_algor)) {
*mga = RSA_MGA_IDENTIFIER_new();
if (*mga != NULL) {
(*mga)->mask_gen = mgf1;
(*mga)->one_way_hash = hash_algor;
return 1;
}
}
OPENSSL_PUT_ERROR(RSA, EVP_R_DECODE_ERROR);
RSA_ALGOR_IDENTIFIER_free(mgf1);
RSA_ALGOR_IDENTIFIER_free(hash_algor);
return 0;
}
// get_context_specific_value sets |*out| to the contents of DER-encoded, ASN.1
// element (not including tag and length bytes) and advances |seq| over it.
// When the tag value does not exist, |seq| gets recovered.
// It returns one when the element exists.
static int get_context_specific_value(CBS *seq, CBS *out, int index) {
unsigned int tag_value = CBS_ASN1_CONTEXT_SPECIFIC | CBS_ASN1_CONSTRUCTED | index;
CBS seq_cp = {seq->data, seq->len};
if (CBS_get_asn1(seq, out, tag_value)) {
return 1;
} else {
// All fields of RSASSA-PSS-params can be absent, which means default.
// Recover |seq|.
seq->data = seq_cp.data;
seq->len = seq_cp.len;
return 0;
}
}
// Decode [0] HashAlgorithm of RSASSA-PSS-params: return one on success and zero
// on failure. See https://tools.ietf.org/html/rfc4055#section-3.1
static int decode_pss_hash(CBS *seq, RSA_ALGOR_IDENTIFIER **hash_algor) {
CBS cs;
if (!get_context_specific_value(seq, &cs, TAG_VALUE_INDEX_0)) {
// HashAlgorithm field can be absent, which means default(sha1) is encoded.
return 1;
}
return decode_one_way_hash(&cs, hash_algor);
}
// Decode [1] MaskGenAlgorithm of RSASSA-PSS-params: return one on success and
// zero on failure. See 3.1. https://tools.ietf.org/html/rfc4055#section-3.1
static int decode_pss_mask_gen(CBS *seq, RSA_MGA_IDENTIFIER **mga) {
CBS cs;
if (!get_context_specific_value(seq, &cs, TAG_VALUE_INDEX_1)) {
// MaskGenAlgorithm field can be absent, which means default(mgf1) is encoded.
return 1;
}
return decode_mask_gen(&cs, mga);
}
static RSA_INTEGER *create_RSA_INTEGER(const int64_t value) {
RSA_INTEGER *rsa_int = RSA_INTEGER_new();
if (rsa_int != NULL) {
rsa_int->value = value;
return rsa_int;
}
return NULL;
}
static int parse_trailer_field(CBS *cbs, RSA_INTEGER **rsa_int) {
int64_t value = 0;
if (CBS_get_asn1_int64(cbs, &value) && CBS_len(cbs) == 0) {
if (value != 1) {
// If present, trailerField field MUST be 1.
OPENSSL_PUT_ERROR(RSA, EVP_R_INVALID_PSS_TRAILER_FIELD);
return 0;
}
*rsa_int = create_RSA_INTEGER(value);
return (*rsa_int) != NULL;
}
OPENSSL_PUT_ERROR(RSA, EVP_R_DECODE_ERROR);
return 0;
}
static int parse_salt_length(CBS *cbs, RSA_INTEGER **rsa_int) {
int64_t value = 0;
if (CBS_get_asn1_int64(cbs, &value) && CBS_len(cbs) == 0) {
if (value < 0) {
// If present, salt length field MUST be non-negative.
OPENSSL_PUT_ERROR(RSA, EVP_R_INVALID_PSS_SALT_LEN);
return 0;
}
*rsa_int = create_RSA_INTEGER(value);
return (*rsa_int) != NULL;
}
OPENSSL_PUT_ERROR(RSA, EVP_R_DECODE_ERROR);
return 0;
}
// Decode [2] saltLength of RSASSA-PSS-params
// See 3.1. https://tools.ietf.org/html/rfc4055#section-3.1
static int decode_pss_salt_len(CBS *seq, RSA_INTEGER **salt_len) {
CBS cs;
if (!get_context_specific_value(seq, &cs, TAG_VALUE_INDEX_2)) {
// saltLength field can be absent, which means default(20) is encoded.
return 1;
}
return parse_salt_length(&cs, salt_len);
}
// Decode [3] trailerField of RSASSA-PSS-params
// See 3.1. https://tools.ietf.org/html/rfc4055#section-3.1
static int decode_pss_trailer_field(CBS *seq, RSA_INTEGER **trailer_field) {
CBS cs;
if (!get_context_specific_value(seq, &cs, TAG_VALUE_INDEX_3)) {
// Trailer field can be absent, which means default(1) is encoded.
return 1;
}
return parse_trailer_field(&cs, trailer_field);
}
// Get RSASSA-PSS-params sequence
// See 3.1. https://tools.ietf.org/html/rfc4055#section-3.1
int RSASSA_PSS_parse_params(CBS *params, RSASSA_PSS_PARAMS **pss_params) {
if (CBS_len(params) == 0) {
// The parameters may be absent.
return 1;
}
RSA_ALGOR_IDENTIFIER *hash_algor = NULL;
RSA_MGA_IDENTIFIER *mask_gen_algor = NULL;
RSA_INTEGER *salt_len = NULL;
RSA_INTEGER *trailer_field = NULL;
CBS seq;
if (CBS_get_asn1(params, &seq, CBS_ASN1_SEQUENCE) &&
(CBS_len(params) == 0) &&
decode_pss_hash(&seq, &hash_algor) &&
decode_pss_mask_gen(&seq, &mask_gen_algor) &&
decode_pss_salt_len(&seq, &salt_len) &&
decode_pss_trailer_field(&seq, &trailer_field) &&
(CBS_len(&seq) == 0)) {
*pss_params = RSASSA_PSS_PARAMS_new();
if ((*pss_params) != NULL) {
(*pss_params)->hash_algor = hash_algor;
(*pss_params)->mask_gen_algor = mask_gen_algor;
(*pss_params)->salt_len = salt_len;
(*pss_params)->trailer_field = trailer_field;
return 1;
}
}
RSA_ALGOR_IDENTIFIER_free(hash_algor);
RSA_MGA_IDENTIFIER_free(mask_gen_algor);
RSA_INTEGER_free(salt_len);
RSA_INTEGER_free(trailer_field);
return 0;
}
// pss_parse_nid return one on success and zero on failure.
// When success and the hash is sha1, |*out| will hold NULL.
// When success and the hash is not sha1, |*out| will hold a newly allocated
// RSA_ALGOR_IDENTIFIER with NID |nid|.
static int pss_parse_nid(int nid, RSA_ALGOR_IDENTIFIER **out) {
if (nid == NID_sha1) {
(*out) = NULL;
return 1;
}
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(rsa_pss_hash_functions); i++) {
const RSA_PSS_SUPPORTED_ALGOR *supported_algor = rsa_pss_hash_functions[i];
if (nid == supported_algor->nid) {
*out = RSA_ALGOR_IDENTIFIER_new();
if ((*out) != NULL) {
(*out)->nid = supported_algor->nid;
return 1;
}
}
}
OPENSSL_PUT_ERROR(RSA, EVP_R_UNSUPPORTED_ALGORITHM);
return 0;
}
RSA_INTEGER *RSA_INTEGER_new(void) {
RSA_INTEGER *ret = OPENSSL_zalloc(sizeof(RSA_INTEGER));
if (ret == NULL) {
return NULL;
}
return ret;
}
RSA_ALGOR_IDENTIFIER *RSA_ALGOR_IDENTIFIER_new(void) {
RSA_ALGOR_IDENTIFIER *ret = OPENSSL_zalloc(sizeof(RSA_ALGOR_IDENTIFIER));
if (ret == NULL) {
return NULL;
}
return ret;
}
RSA_MGA_IDENTIFIER *RSA_MGA_IDENTIFIER_new(void) {
RSA_MGA_IDENTIFIER *ret = OPENSSL_zalloc(sizeof(RSA_MGA_IDENTIFIER));
if (ret == NULL) {
return NULL;
}
return ret;
}
RSASSA_PSS_PARAMS *RSASSA_PSS_PARAMS_new(void) {
RSASSA_PSS_PARAMS *ret = OPENSSL_zalloc(sizeof(RSASSA_PSS_PARAMS));
if (ret == NULL) {
return NULL;
}
return ret;
}
void RSA_INTEGER_free(RSA_INTEGER *ptr) {
OPENSSL_free(ptr);
}
void RSA_ALGOR_IDENTIFIER_free(RSA_ALGOR_IDENTIFIER *algor) {
OPENSSL_free(algor);
}
void RSA_MGA_IDENTIFIER_free(RSA_MGA_IDENTIFIER *mga) {
if (mga == NULL) {
return;
}
RSA_ALGOR_IDENTIFIER_free(mga->mask_gen);
RSA_ALGOR_IDENTIFIER_free(mga->one_way_hash);
OPENSSL_free(mga);
}
void RSASSA_PSS_PARAMS_free(RSASSA_PSS_PARAMS *params) {
if (params == NULL) {
return;
}
RSA_ALGOR_IDENTIFIER_free(params->hash_algor);
RSA_MGA_IDENTIFIER_free(params->mask_gen_algor);
RSA_INTEGER_free(params->salt_len);
RSA_INTEGER_free(params->trailer_field);
OPENSSL_free(params);
}
// pss_hash_create returns one on success and zero on failure.
// When success and the given algorithm is not default (sha1), |*out| will hold
// the allocated RSA_ALGOR_IDENTIFIER.
static int pss_hash_create(const EVP_MD *sigmd, RSA_ALGOR_IDENTIFIER **out) {
if (sigmd == NULL) {
*out = NULL;
return 1;
}
return pss_parse_nid(EVP_MD_type(sigmd), out);
}
// pss_mga_create returns one on success and zero on failure.
// When success and the given algorithm is not default (sha1), *out will hold
// the allocated RSA_ALGOR_IDENTIFIER.
static int pss_mga_create(const EVP_MD *mgf1md, RSA_MGA_IDENTIFIER **out) {
if (mgf1md == NULL || EVP_MD_type(mgf1md) == NID_sha1) {
*out = NULL;
return 1;
}
RSA_MGA_IDENTIFIER *mga = RSA_MGA_IDENTIFIER_new();
if (mga == NULL) {
return 0;
}
if (pss_parse_nid(EVP_MD_type(mgf1md), &(mga->one_way_hash))) {
*out = mga;
return 1;
}
RSA_MGA_IDENTIFIER_free(mga);
return 0;
}
// pss_saltlen_create returns one on success and zero on failure.
// When success and the given length |saltlen| is not default (20), |*out| will
// hold the newly allocated RSA_INTEGER.
static int pss_saltlen_create(int saltlen, RSA_INTEGER **out) {
if (saltlen < 0) {
return 0;
}
if (saltlen == PSS_DEFAULT_SALT_LEN) {
return 1;
}
*out = RSA_INTEGER_new();
if (*out != NULL) {
(*out)->value = saltlen;
return 1;
}
return 0;
}
int RSASSA_PSS_PARAMS_create(const EVP_MD *sigmd, const EVP_MD *mgf1md,
int saltlen, RSASSA_PSS_PARAMS **out) {
// If all parameters are not changed after |pkey_rsa_init|, don't create pss.
if (sigmd == NULL && mgf1md == NULL && saltlen == -2) {
return 1;
}
RSASSA_PSS_PARAMS *pss = RSASSA_PSS_PARAMS_new();
if (pss == NULL) {
return 0;
}
if (!pss_hash_create(sigmd, &pss->hash_algor) ||
!pss_mga_create(mgf1md, &pss->mask_gen_algor) ||
!pss_saltlen_create(saltlen, &pss->salt_len)) {
RSASSA_PSS_PARAMS_free(pss);
return 0;
}
*out = pss;
return 1;
}
// nid_to_EVP_MD maps |nid| to the corresponding |EVP_md()| supported by pss.
// It returns NULL if the |nid| is not supported.
static const EVP_MD *nid_to_EVP_MD(const int nid) {
switch (nid) {
case NID_sha1:
return EVP_sha1();
case NID_sha224:
return EVP_sha224();
case NID_sha256:
return EVP_sha256();
case NID_sha384:
return EVP_sha384();
case NID_sha512:
return EVP_sha512();
default:
OPENSSL_PUT_ERROR(RSA, EVP_R_UNSUPPORTED_ALGORITHM);
return NULL;
}
}
// hash_algor_to_EVP_MD return one on success and zero on failure.
// When success, |*md| will be assigned with the corresponding EVP_md()
// or the default EVP_sha1() in case hash_algor is not provided.
static int hash_algor_to_EVP_MD(RSA_ALGOR_IDENTIFIER *hash_algor,
const EVP_MD **md) {
if (hash_algor) {
*md = nid_to_EVP_MD(hash_algor->nid);
} else {
*md = EVP_sha1();
}
return *md != NULL;
}
int RSASSA_PSS_PARAMS_get(const RSASSA_PSS_PARAMS *pss, const EVP_MD **md,
const EVP_MD **mgf1md, int *saltlen) {
if (pss == NULL || md == NULL || mgf1md == NULL || saltlen == NULL) {
return 0;
}
if (!hash_algor_to_EVP_MD(pss->hash_algor, md)) {
return 0;
}
RSA_ALGOR_IDENTIFIER *mga_hash = NULL;
if (pss->mask_gen_algor) {
mga_hash = pss->mask_gen_algor->one_way_hash;
}
if (!hash_algor_to_EVP_MD(mga_hash, mgf1md)) {
return 0;
}
if (pss->salt_len) {
if (pss->salt_len->value < 0) {
OPENSSL_PUT_ERROR(RSA, EVP_R_INVALID_PSS_SALT_LEN);
return 0;
}
*saltlen = pss->salt_len->value;
} else {
*saltlen = PSS_DEFAULT_SALT_LEN;
}
if (pss->trailer_field &&
pss->trailer_field->value != PSS_TRAILER_FIELD_VALUE) {
OPENSSL_PUT_ERROR(RSA, EVP_R_INVALID_PSS_TRAILER_FIELD);
return 0;
}
return 1;
}

View File

@@ -0,0 +1,626 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0 OR ISC
#include <openssl/base.h>
#include <gtest/gtest.h>
#include <openssl/bytestring.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/nid.h>
#include "internal.h"
// Below test inputs are created by running 'openssl req -x509',
// and then exacting the bytes of RSASSA-PSS-params from generated results.
// pss_sha1_salt_absent is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha1 (absent)
// Mask Algorithm: mgf1 with sha1 (absent)
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
static const uint8_t pss_sha1_salt_absent[] = {0x30, 0x00};
// pss_sha224_salt_absent is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha224
// Mask Algorithm: mgf1 with sha224
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
static const uint8_t pss_sha224_salt_absent[] = {
0x30, 0x2b, 0xa0, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x04, 0xa1, 0x1a, 0x30, 0x18, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0b, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04};
// pss_sha256_salt_absent is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha256
// Mask Algorithm: mgf1 with sha256
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
static const uint8_t pss_sha256_salt_absent[] = {
0x30, 0x2B, 0xA0, 0x0D, 0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x01, 0xA1, 0x1A, 0x30, 0x18, 0x06, 0x09, 0x2A,
0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x0B, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01};
// pss_sha384_salt_absent is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha384
// Mask Algorithm: mgf1 with sha384
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
static const uint8_t pss_sha384_salt_absent[] = {
0x30, 0x2B, 0xA0, 0x0D, 0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x02, 0xA1, 0x1A, 0x30, 0x18, 0x06, 0x09, 0x2A,
0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x0B, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02};
// pss_sha512_salt_absent is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha512
// Mask Algorithm: mgf1 with sha512
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
static const uint8_t pss_sha512_salt_absent[] = {
0x30, 0x2B, 0xA0, 0x0D, 0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x03, 0xA1, 0x1A, 0x30, 0x18, 0x06, 0x09, 0x2A,
0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x0B, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03};
// pss_sha256_salt_default is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha256
// Mask Algorithm: mgf1 with sha256
// Minimum Salt Length: 0x14 (default)
// Trailer Field: 0x01 (absent)
static const uint8_t pss_sha256_salt_default[] = {
0x30, 0x30, 0xa0, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0xa1, 0x1a, 0x30,
0x18, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x08, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x01, 0xa2, 0x03, 0x02, 0x01, 0x14};
// pss_sha256_salt_30 is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha256
// Mask Algorithm: mgf1 with sha256
// Minimum Salt Length: 0x1e (30)
// Trailer Field: 0x01 (absent)
static const uint8_t pss_sha256_salt_30[] = {
0x30, 0x30, 0xa0, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0xa1, 0x1a, 0x30,
0x18, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
0x01, 0x08, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x01, 0xa2, 0x03, 0x02, 0x01, 0x1e};
// Below test inputs are created by the Java sample code.
// Java uses NULL to encode parameters of Hash func.
// ```JDK11
// Signature signatureSHA256Java = Signature.getInstance("RSASSA-PSS")
// PSSParameterSpec pssParameterSpec = new PSSParameterSpec("SHA-256", "MGF1", MGF1ParameterSpec.SHA256, 0, 1);
// signatureSHA256Java.setParameter(pssParameterSpec);
// byte[] bytes = signatureSHA256Java.getParameters().getEncoded();
// ```
// jdk_pss_sha256_salt_0 is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha256
// Mask Algorithm: mgf1 with sha256
// Minimum Salt Length: 0x00 (0)
// Trailer Field: 0x01 (absent)
static const uint8_t jdk_pss_sha256_salt_0[] = {
0x30, 0x34, 0xA0, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xA1, 0x1C, 0x30,
0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
0x08, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
0x04, 0x02, 0x01, 0x05, 0x00, 0xA2, 0x03, 0x02, 0x01, 0x00};
// jdk_pss_sha256_salt_absent is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha256
// Mask Algorithm: mgf1 with sha256
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
static const uint8_t jdk_pss_sha256_salt_absent[] = {
0x30, 0x2F, 0xA0, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xA1,
0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x01, 0x08, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00};
// jdk_pss_sha256_salt_30 is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha256
// Mask Algorithm: mgf1 with sha256
// Minimum Salt Length: 0x1e (30)
// Trailer Field: 0x01 (absent)
static const uint8_t jdk_pss_sha256_salt_30[] = {
0x30, 0x34, 0xA0, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48,
0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xA1, 0x1C, 0x30,
0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
0x08, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
0x04, 0x02, 0x01, 0x05, 0x00, 0xA2, 0x03, 0x02, 0x01, 0x1E};
// jdk_pss_sha224_salt_absent is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha224
// Mask Algorithm: mgf1 with sha224
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
static const uint8_t jdk_pss_sha224_salt_absent[] = {
0x30, 0x2F, 0xA0, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0xA1,
0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x01, 0x08, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00};
// jdk_pss_sha384_salt_absent is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha384
// Mask Algorithm: mgf1 with sha384
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
static const uint8_t jdk_pss_sha384_salt_absent[] = {
0x30, 0x2F, 0xA0, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0xA1,
0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x01, 0x08, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00};
// jdk_pss_sha512_salt_absent is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha512
// Mask Algorithm: mgf1 with sha512
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
static const uint8_t jdk_pss_sha512_salt_absent[] = {
0x30, 0x2F, 0xA0, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0xA1,
0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x01, 0x08, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00};
// jdk_pss_sha256_mgf1_sha512 is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha256
// Mask Algorithm: mgf1 with sha512
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
// This is to test params decode when different hash funcs are used.
static const uint8_t jdk_pss_sha256_mgf1_sha512[] = {
0x30, 0x2F, 0xA0, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0xA1,
0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7,
0x0D, 0x01, 0x01, 0x08, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00};
// jdk_pss_sha1_mgf1_sha256 is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha1 (absent)
// Mask Algorithm: mgf1 with sha256
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
// This is to test params decode when different hash funcs are used, and one
// hash func is the default (sha1), which is omitted during encode.
static const uint8_t jdk_pss_sha1_mgf1_sha256[] = {
0x30, 0x1E, 0xA1, 0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48,
0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x0D, 0x06, 0x09, 0x60,
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00};
// jdk_pss_sha256_mgf1_sha1 is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha256
// Mask Algorithm: mgf1 with sha1 (absent)
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (absent)
// This is to test params decode when different hash funcs are used, and one
// hash func is the default (sha1), which is omitted during encode.
static const uint8_t jdk_pss_sha256_mgf1_sha1[] = {
0x30, 0x11, 0xA0, 0x0F, 0x30, 0x0D, 0x06, 0x09, 0x60, 0x86,
0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00};
// jdk_pss_sha1_mgf1_sha1_salt_30 is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha1 (absent)
// Mask Algorithm: mgf1 with sha1 (absent)
// Minimum Salt Length: 0x1e (30)
// Trailer Field: 0x01 (absent)
static const uint8_t jdk_pss_sha1_mgf1_sha1_salt_30[] = {
0x30, 0x05, 0xA2, 0x03, 0x02, 0x01, 0x1E};
// These bytes are manually created for test purpose.
// pss_with_trailer_field_1 is a DER-encoded RSASSA-PSS-params:
// Hash Algorithm: sha1 (absent)
// Mask Algorithm: mgf1 with sha1 (absent)
// Minimum Salt Length: 0x14 (absent)
// Trailer Field: 0x01 (default, not absent)
static const uint8_t pss_with_trailer_field_1[] = {
0x30, 0x05, 0xA3, 0x03, 0x02, 0x01, 0x01};
// Invalid test inputs:
// invalid_pss_salt_missing is created by removing salt field from
// pss_sha256_salt_20. This is invalid because "type-length-value" cannot
// reconcile "length" and "value".
static const uint8_t invalid_pss_salt_missing[] = {
0x30, 0x30, 0xa0, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x01, 0xa1, 0x1a, 0x30, 0x18, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0b, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01};
// pss_with_invalid_sha256_oid is created by changing sha512 oid
// from 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
// to 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x05.
static const uint8_t pss_with_invalid_sha256_oid[] = {
0x30, 0x2b, 0xa0, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x05, 0xa1, 0x1a, 0x30, 0x18, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08, 0x30, 0x0b, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04};
// pss_with_invalid_mgf1_oid is created by changing mgf1 oid
// from 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x08
// to 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x09.
static const uint8_t pss_with_invalid_mgf1_oid[] = {
0x30, 0x2b, 0xa0, 0x0d, 0x30, 0x0b, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01,
0x65, 0x03, 0x04, 0x02, 0x04, 0xa1, 0x1a, 0x30, 0x18, 0x06, 0x09, 0x2a,
0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x09, 0x30, 0x0b, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04};
// pss_with_tag2_before_tag0 has tag [2] before tag [0].
static const uint8_t pss_with_tag2_before_tag0[] = {
0x30, 0x34, 0xA2, 0x03, 0x02, 0x01, 0x1E, 0xA0, 0x0F, 0x30, 0x0D,
0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01,
0x05, 0x00, 0xA1, 0x1C, 0x30, 0x1A, 0x06, 0x09, 0x2A, 0x86, 0x48,
0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x0D, 0x06, 0x09, 0x60,
0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00
};
// pss_with_tag4 has tag [4].
static const uint8_t pss_with_tag4[] = {
0x30, 0x05, 0xA4, 0x03, 0x02, 0x01, 0x1E};
// pss_with_double_salt_30 has two tag[2].
static const uint8_t pss_with_double_salt_30[] = {
0x30, 0x0A, 0xA2, 0x03, 0x02, 0x01, 0x1E, 0xA2, 0x03, 0x02, 0x01, 0x1E};
// pss_with_sequence_length_too_short should use 0x05 as length instead of 0x04.
// This invalid bytes are modified from jdk_pss_sha1_mgf1_sha1_salt_30.
static const uint8_t pss_with_sequence_length_too_short[] = {
0x30, 0x04, 0xA2, 0x03, 0x02, 0x01, 0x1E};
// pss_with_sequence_length_too_long should use 0x05 as length instead of 0x06.
// This invalid bytes are modified from jdk_pss_sha1_mgf1_sha1_salt_30.
static const uint8_t pss_with_sequence_length_too_long[] = {
0x30, 0x06, 0xA2, 0x03, 0x02, 0x01, 0x1E};
// pss_with_tag2_length_too_short should use 0x03 as tag2 length instead of 0x02.
// This invalid bytes are modified from jdk_pss_sha1_mgf1_sha1_salt_30.
static const uint8_t pss_with_tag2_length_too_short[] = {
0x30, 0x05, 0xA2, 0x02, 0x02, 0x01, 0x1E};
// pss_with_tag2_length_too_long should use 0x03 as tag2 length instead of 0x04.
// This invalid bytes are modified from jdk_pss_sha1_mgf1_sha1_salt_30.
static const uint8_t pss_with_tag2_length_too_long[] = {
0x30, 0x05, 0xA2, 0x04, 0x02, 0x01, 0x1E};
// pss_with_negative_salt_length is modified from jdk_pss_sha1_mgf1_sha1_salt_30.
static const uint8_t pss_with_negative_salt_length[] = {
0x30, 0x05, 0xA2, 0x03, 0x02, 0x01, 0xFF};
// pss_with_negative_salt_length is modified from jdk_pss_sha1_mgf1_sha1_salt_30.
static const uint8_t pss_with_trailer_field_not_1[] = {
0x30, 0x05, 0xA3, 0x03, 0x02, 0x01, 0x02};
static const int omit_salt_len = -1;
struct PssParseTestInput {
const uint8_t *der;
size_t der_len;
int expected_hash_nid;
int expected_mask_gen_nid;
int expected_mgf1_hash_nid;
int expected_salt_len;
} kPssParseTestInputs[] = {
{pss_sha1_salt_absent, sizeof(pss_sha1_salt_absent), NID_undef, NID_undef,
NID_undef, omit_salt_len},
{pss_sha224_salt_absent, sizeof(pss_sha224_salt_absent), NID_sha224,
NID_mgf1, NID_sha224, omit_salt_len},
{pss_sha256_salt_absent, sizeof(pss_sha256_salt_absent), NID_sha256,
NID_mgf1, NID_sha256, omit_salt_len},
{pss_sha384_salt_absent, sizeof(pss_sha384_salt_absent), NID_sha384,
NID_mgf1, NID_sha384, omit_salt_len},
{pss_sha512_salt_absent, sizeof(pss_sha512_salt_absent), NID_sha512,
NID_mgf1, NID_sha512, omit_salt_len},
{pss_sha256_salt_default, sizeof(pss_sha256_salt_default), NID_sha256,
NID_mgf1, NID_sha256, PSS_DEFAULT_SALT_LEN},
{pss_sha256_salt_30, sizeof(pss_sha256_salt_30), NID_sha256, NID_mgf1,
NID_sha256, 30},
{jdk_pss_sha256_salt_0, sizeof(jdk_pss_sha256_salt_0), NID_sha256, NID_mgf1,
NID_sha256, 0},
{jdk_pss_sha256_salt_absent, sizeof(jdk_pss_sha256_salt_absent), NID_sha256,
NID_mgf1, NID_sha256, omit_salt_len},
{jdk_pss_sha256_salt_30, sizeof(jdk_pss_sha256_salt_30), NID_sha256,
NID_mgf1, NID_sha256, 30},
{jdk_pss_sha224_salt_absent, sizeof(jdk_pss_sha224_salt_absent), NID_sha224,
NID_mgf1, NID_sha224, omit_salt_len},
{jdk_pss_sha384_salt_absent, sizeof(jdk_pss_sha384_salt_absent), NID_sha384,
NID_mgf1, NID_sha384, omit_salt_len},
{jdk_pss_sha512_salt_absent, sizeof(jdk_pss_sha512_salt_absent), NID_sha512,
NID_mgf1, NID_sha512, omit_salt_len},
{jdk_pss_sha256_mgf1_sha512, sizeof(jdk_pss_sha256_mgf1_sha512), NID_sha256,
NID_mgf1, NID_sha512, omit_salt_len},
{jdk_pss_sha1_mgf1_sha256, sizeof(jdk_pss_sha1_mgf1_sha256), NID_undef,
NID_mgf1, NID_sha256, omit_salt_len},
{jdk_pss_sha256_mgf1_sha1, sizeof(jdk_pss_sha256_mgf1_sha1), NID_sha256,
NID_undef, NID_undef, omit_salt_len},
{jdk_pss_sha1_mgf1_sha1_salt_30, sizeof(jdk_pss_sha1_mgf1_sha1_salt_30), NID_undef,
NID_undef, NID_undef, 30},
};
class PssParseTest : public testing::TestWithParam<PssParseTestInput> {};
TEST_P(PssParseTest, DecodeParamsDer) {
const auto &param = GetParam();
CBS params;
params.data = param.der;
params.len = param.der_len;
RSASSA_PSS_PARAMS *pss = nullptr;
ASSERT_TRUE(RSASSA_PSS_parse_params(&params, &pss));
// Holds ownership of heap-allocated RSASSA_PSS_PARAMS.
bssl::UniquePtr<RSASSA_PSS_PARAMS> pss_ptr(pss);
// Expect all bytes of params are consumed.
ASSERT_FALSE(CBS_len(&params));
// Validate Hash Algorithm of RSASSA-PSS-params.
if (param.expected_hash_nid != NID_undef) {
ASSERT_TRUE(pss->hash_algor);
EXPECT_EQ(pss->hash_algor->nid, param.expected_hash_nid);
} else {
// When no expectation, make sure this value is absent.
EXPECT_FALSE(pss->hash_algor);
}
// Validate Mask Algorithm of RSASSA-PSS-params.
RSA_MGA_IDENTIFIER *mga = pss->mask_gen_algor;
if (param.expected_mask_gen_nid != NID_undef) {
ASSERT_TRUE(mga);
ASSERT_TRUE(mga->mask_gen);
EXPECT_EQ(mga->mask_gen->nid, param.expected_mask_gen_nid);
// Validate Hash Algorithm of Mask Gen.
if (param.expected_mgf1_hash_nid) {
ASSERT_TRUE(mga->one_way_hash);
EXPECT_EQ(mga->one_way_hash->nid, param.expected_mgf1_hash_nid);
} else {
// When no expectation, make sure this value is absent.
EXPECT_FALSE(mga->one_way_hash);
}
} else {
// When no expectation, make sure this value is absent.
EXPECT_FALSE(mga);
}
// Validate Minimum Salt Length of RSASSA-PSS-params.
if (param.expected_salt_len != omit_salt_len) {
ASSERT_TRUE(pss->salt_len);
EXPECT_EQ(pss->salt_len->value, param.expected_salt_len);
} else {
// When no expectation, make sure this value is absent.
EXPECT_FALSE(pss->salt_len);
}
// Perform signature generation MUST omit the trailerField field.
// https://tools.ietf.org/html/rfc4055#page-8
EXPECT_FALSE(pss->trailer_field);
}
INSTANTIATE_TEST_SUITE_P(RsassaPssAll, PssParseTest,
testing::ValuesIn(kPssParseTestInputs));
struct InvalidPssParseInput {
const uint8_t *der;
size_t der_len;
} kInvalidPssParseInputs[] = {
{invalid_pss_salt_missing, sizeof(invalid_pss_salt_missing)},
{pss_with_invalid_sha256_oid, sizeof(pss_with_invalid_sha256_oid)},
{pss_with_invalid_mgf1_oid, sizeof(pss_with_invalid_mgf1_oid)},
{pss_with_tag2_before_tag0, sizeof(pss_with_tag2_before_tag0)},
{pss_with_tag4, sizeof(pss_with_tag4)},
{pss_with_double_salt_30, sizeof(pss_with_double_salt_30)},
{pss_with_sequence_length_too_short, sizeof(pss_with_sequence_length_too_short)},
{pss_with_sequence_length_too_long, sizeof(pss_with_sequence_length_too_long)},
{pss_with_tag2_length_too_short, sizeof(pss_with_tag2_length_too_short)},
{pss_with_tag2_length_too_long, sizeof(pss_with_tag2_length_too_long)},
{pss_with_negative_salt_length, sizeof(pss_with_negative_salt_length)},
{pss_with_trailer_field_not_1, sizeof(pss_with_trailer_field_not_1)},
};
class InvalidPssParseTest
: public testing::TestWithParam<InvalidPssParseInput> {};
TEST_P(InvalidPssParseTest, DecodeInvalidDer) {
const auto &param = GetParam();
CBS params;
params.data = param.der;
params.len = param.der_len;
RSASSA_PSS_PARAMS *pss = nullptr;
ASSERT_FALSE(RSASSA_PSS_parse_params(&params, &pss));
ERR_clear_error();
}
INSTANTIATE_TEST_SUITE_P(RsassaPssAll, InvalidPssParseTest,
testing::ValuesIn(kInvalidPssParseInputs));
struct PssConversionTestInput {
const EVP_MD *md;
int saltlen;
int expect_pss_is_null;
int expect_pss_hash_is_null;
int expect_pss_saltlen_is_null;
} kPssConversionTestInputs[] = {
{EVP_sha1(), PSS_DEFAULT_SALT_LEN, 0, 1, 1},
{EVP_sha224(), 30, 0, 0, 0},
{EVP_sha256(), 30, 0, 0, 0},
{EVP_sha384(), 30, 0, 0, 0},
{EVP_sha512(), 30, 0, 0, 0},
// This test case happens in |pkey_rsa_init| of |p_rsa.c|.
{nullptr, -2, 1, 1, 1},
};
static void test_RSASSA_PSS_PARAMS_get(RSASSA_PSS_PARAMS *pss,
const EVP_MD *expect_md,
int expect_saltlen) {
const EVP_MD *sigmd = nullptr;
const EVP_MD *mgf1md = nullptr;
int saltlen = -1;
ASSERT_TRUE(RSASSA_PSS_PARAMS_get(pss, &sigmd, &mgf1md, &saltlen));
EXPECT_EQ(sigmd, expect_md);
EXPECT_EQ(mgf1md, expect_md);
EXPECT_EQ(saltlen, expect_saltlen);
}
class PssConversionTest : public testing::TestWithParam<PssConversionTestInput> {};
// This test is to check the conversion between |RSASSA_PSS_PARAMS| and
// (|*sigmd|, |*mgf1md| and |saltlen|), which are fields of |RSA_PKEY_CTX|.
// The 1st step is to validate |RSASSA_PSS_PARAMS_create|.
// The 2nd step is to validate |RSASSA_PSS_PARAMS_get|.
TEST_P(PssConversionTest, CreationAndGetSuccess) {
const auto &param = GetParam();
RSASSA_PSS_PARAMS *pss = nullptr;
const EVP_MD *md = param.md;
int saltlen = param.saltlen;
// STEP 1: validate |RSASSA_PSS_PARAMS_create|.
ASSERT_TRUE(RSASSA_PSS_PARAMS_create(md, md, saltlen, &pss));
// Validate if the pss should be allocated.
if (param.expect_pss_is_null) {
ASSERT_FALSE(pss);
return;
} else {
ASSERT_TRUE(pss);
}
// Holds ownership of heap-allocated RSASSA_PSS_PARAMS.
bssl::UniquePtr<RSASSA_PSS_PARAMS> pss_ptr(pss);
// Validate the hash_algor of pss.
if (param.expect_pss_hash_is_null) {
// hash_algor is NULL when the default value (sha1) is passed.
// Pss params encode expects this default value is omitted.
// See 3.1. https://tools.ietf.org/html/rfc4055#section-3.1
// MUST omit the hashAlgorithm field when SHA-1 is used.
EXPECT_FALSE(pss->hash_algor);
EXPECT_FALSE(pss->mask_gen_algor);
} else {
ASSERT_TRUE(pss->hash_algor);
ASSERT_TRUE(pss->mask_gen_algor);
ASSERT_TRUE(pss->mask_gen_algor->one_way_hash);
EXPECT_EQ(pss->hash_algor->nid, EVP_MD_type(md));
EXPECT_EQ(pss->mask_gen_algor->one_way_hash->nid, EVP_MD_type(md));
}
// Validate the saltlen of pss.
if (param.expect_pss_saltlen_is_null) {
// salt_len is NULL when the default value (20) is passed.
// Pss params encode expects the default value to be omitted.
// This is not a MUST but it is implemented in OpenSSL.
EXPECT_FALSE(pss->salt_len);
} else {
ASSERT_TRUE(pss->salt_len);
EXPECT_EQ(pss->salt_len->value, saltlen);
}
// Trailer field should not be set because it's for encoding only.
// See 3.1. https://tools.ietf.org/html/rfc4055#section-3.1
// MUST omit the trailerField field.
EXPECT_FALSE(pss->trailer_field);
// STEP 2: validate |RSASSA_PSS_PARAMS_get|.
// Validate the conversion from |RSASSA_PSS_PARAMS| to
// (|*sigmd|, |*mgf1md| and |saltlen|).
test_RSASSA_PSS_PARAMS_get(pss, md, saltlen);
}
INSTANTIATE_TEST_SUITE_P(RsassaPssAll, PssConversionTest,
testing::ValuesIn(kPssConversionTestInputs));
TEST(RsassaPssTest, DecodeParamsDerWithTrailerField) {
CBS params;
params.data = pss_with_trailer_field_1;
params.len = sizeof(pss_with_trailer_field_1);
RSASSA_PSS_PARAMS *pss = nullptr;
ASSERT_TRUE(RSASSA_PSS_parse_params(&params, &pss));
// Holds ownership of heap-allocated RSASSA_PSS_PARAMS.
bssl::UniquePtr<RSASSA_PSS_PARAMS> pss_ptr(pss);
// Expect all bytes of params are used.
ASSERT_FALSE(CBS_len(&params));
// Validate Hash Algorithm of RSASSA-PSS-params.
EXPECT_FALSE(pss->hash_algor);
// Validate Mask Algorithm of RSASSA-PSS-params.
EXPECT_FALSE(pss->mask_gen_algor);
// Validate Salt Length of RSASSA-PSS-params.
EXPECT_FALSE(pss->salt_len);
// Validate Trailer field of RSASSA-PSS-params.
ASSERT_TRUE(pss->trailer_field);
EXPECT_EQ(pss->trailer_field->value, PSS_TRAILER_FIELD_VALUE);
}
struct InvalidPssCreateTestInput {
const EVP_MD *md;
int saltlen;
} kInvalidPssCreateTestInputs[] = {
// Expect test fails because saltlen cannot be negative.
{EVP_sha256(), -1},
// Expect test fails because md5 is not supported.
{EVP_md5(), PSS_DEFAULT_SALT_LEN},
};
class InvalidPssCreateTest
: public testing::TestWithParam<InvalidPssCreateTestInput> {};
TEST_P(InvalidPssCreateTest, CreationFailure) {
const auto &param = GetParam();
RSASSA_PSS_PARAMS *pss = nullptr;
const EVP_MD *md = param.md;
int saltlen = param.saltlen;
ASSERT_FALSE(RSASSA_PSS_PARAMS_create(md, md, saltlen, &pss));
ASSERT_FALSE(pss);
ERR_clear_error();
}
INSTANTIATE_TEST_SUITE_P(RsassaPssAll, InvalidPssCreateTest,
testing::ValuesIn(kInvalidPssCreateTestInputs));
struct InvalidPssGetTestInput {
int nid;
int saltlen;
int trailerfiled;
} kInvalidPssGetTestInputs[] = {
// Expect test fails because md5 is not supported.
{NID_md5, PSS_DEFAULT_SALT_LEN, PSS_TRAILER_FIELD_VALUE},
// Expect test fails because saltlen cannot be negative.
{NID_sha256, -1, PSS_TRAILER_FIELD_VALUE},
// Expect test fails because trailer field MUST be 1.
{NID_sha256, PSS_DEFAULT_SALT_LEN, 2},
};
class InvalidPssGetTest
: public testing::TestWithParam<InvalidPssGetTestInput> {};
TEST_P(InvalidPssGetTest, GetFailure) {
const auto &param = GetParam();
RSA_ALGOR_IDENTIFIER pss_hash = {param.nid};
RSA_MGA_IDENTIFIER pss_mga = {nullptr, &pss_hash};
RSA_INTEGER pss_saltlen = {param.saltlen};
RSA_INTEGER pss_trailer_field = {param.trailerfiled};
RSASSA_PSS_PARAMS pss = {
&pss_hash,
&pss_mga,
&pss_saltlen,
&pss_trailer_field,
};
const EVP_MD *sigmd = nullptr;
const EVP_MD *mgf1md = nullptr;
int saltlen = -1;
ASSERT_FALSE(RSASSA_PSS_PARAMS_get(&pss, &sigmd, &mgf1md, &saltlen));
ERR_clear_error();
}
INSTANTIATE_TEST_SUITE_P(RsassaPssAll, InvalidPssGetTest,
testing::ValuesIn(kInvalidPssGetTestInputs));
TEST(InvalidPssGetTest, PssIsNull) {
const EVP_MD *sigmd = nullptr;
const EVP_MD *mgf1md = nullptr;
int saltlen = -1;
ASSERT_FALSE(RSASSA_PSS_PARAMS_get(nullptr, &sigmd, &mgf1md, &saltlen));
ERR_clear_error();
}
TEST(PssGetTest, AllParamsAbsent) {
RSASSA_PSS_PARAMS pss = {
nullptr,
nullptr,
nullptr,
nullptr,
};
test_RSASSA_PSS_PARAMS_get(&pss, EVP_sha1(), PSS_DEFAULT_SALT_LEN);
}