Add an EC J-PAKE KDF to transform K -> SHA256(K.X) for TLS 1.2
TLS uses it to derive the session secret. The algorithm takes a serialized point in an uncompressed form, extracts the X coordinate and computes SHA256 of it. It is only expected to work with P-256. Fixes #5978. Signed-off-by: Andrzej Kurek <andrzej.kurek@arm.com>
This commit is contained in:
parent
f6a6a2d815
commit
08d34b8693
7 changed files with 129 additions and 11 deletions
|
@ -228,6 +228,12 @@ extern "C" {
|
||||||
#endif /* !MBEDTLS_PSA_ACCEL_ALG_TLS12_PSK_TO_MS */
|
#endif /* !MBEDTLS_PSA_ACCEL_ALG_TLS12_PSK_TO_MS */
|
||||||
#endif /* PSA_WANT_ALG_TLS12_PSK_TO_MS */
|
#endif /* PSA_WANT_ALG_TLS12_PSK_TO_MS */
|
||||||
|
|
||||||
|
#if defined(PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
#if !defined(MBEDTLS_PSA_ACCEL_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
#define MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS 1
|
||||||
|
#endif /* !MBEDTLS_PSA_ACCEL_ALG_TLS12_ECJPAKE_TO_PMS */
|
||||||
|
#endif /* PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS */
|
||||||
|
|
||||||
#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR)
|
#if defined(PSA_WANT_KEY_TYPE_ECC_KEY_PAIR)
|
||||||
#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR)
|
#if !defined(MBEDTLS_PSA_ACCEL_KEY_TYPE_ECC_KEY_PAIR)
|
||||||
#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR 1
|
#define MBEDTLS_PSA_BUILTIN_KEY_TYPE_ECC_KEY_PAIR 1
|
||||||
|
@ -629,6 +635,8 @@ extern "C" {
|
||||||
#define PSA_WANT_ALG_TLS12_PRF 1
|
#define PSA_WANT_ALG_TLS12_PRF 1
|
||||||
#define MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS 1
|
#define MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS 1
|
||||||
#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1
|
#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1
|
||||||
|
#define MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS 1
|
||||||
|
#define PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS 1
|
||||||
#endif /* MBEDTLS_MD_C */
|
#endif /* MBEDTLS_MD_C */
|
||||||
|
|
||||||
#if defined(MBEDTLS_MD5_C)
|
#if defined(MBEDTLS_MD5_C)
|
||||||
|
|
|
@ -88,6 +88,8 @@
|
||||||
#define PSA_WANT_ALG_STREAM_CIPHER 1
|
#define PSA_WANT_ALG_STREAM_CIPHER 1
|
||||||
#define PSA_WANT_ALG_TLS12_PRF 1
|
#define PSA_WANT_ALG_TLS12_PRF 1
|
||||||
#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1
|
#define PSA_WANT_ALG_TLS12_PSK_TO_MS 1
|
||||||
|
#define PSA_WANT_ALG_TLS12_ECJPAKE_TO_PMS 1
|
||||||
|
|
||||||
/* PBKDF2-HMAC is not yet supported via the PSA API in Mbed TLS.
|
/* PBKDF2-HMAC is not yet supported via the PSA API in Mbed TLS.
|
||||||
* Note: when adding support, also adjust include/mbedtls/config_psa.h */
|
* Note: when adding support, also adjust include/mbedtls/config_psa.h */
|
||||||
//#define PSA_WANT_ALG_XTS 1
|
//#define PSA_WANT_ALG_XTS 1
|
||||||
|
|
|
@ -239,6 +239,15 @@
|
||||||
*/
|
*/
|
||||||
#define PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE 128
|
#define PSA_TLS12_PSK_TO_MS_PSK_MAX_SIZE 128
|
||||||
|
|
||||||
|
/* The expected size of input passed to psa_tls12_ecjpake_to_pms_input,
|
||||||
|
* which is expected to work with P-256 curve only. */
|
||||||
|
#define PSA_TLS12_ECJPAKE_TO_PMS_INPUT_SIZE 65
|
||||||
|
|
||||||
|
/* The size of a serialized K.X coordinate to be used in
|
||||||
|
* psa_tls12_ecjpake_to_pms_input. This function only accepts the P-256
|
||||||
|
* curve. */
|
||||||
|
#define PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE 32
|
||||||
|
|
||||||
/** The maximum size of a block cipher. */
|
/** The maximum size of a block cipher. */
|
||||||
#define PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE 16
|
#define PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE 16
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,12 @@ typedef struct
|
||||||
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF ||
|
#endif /* MBEDTLS_PSA_BUILTIN_ALG_HKDF ||
|
||||||
MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT ||
|
MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXTRACT ||
|
||||||
MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND */
|
MBEDTLS_PSA_BUILTIN_ALG_HKDF_EXPAND */
|
||||||
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
uint8_t MBEDTLS_PRIVATE(data)[PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE];
|
||||||
|
} psa_tls12_ecjpake_to_pms_t;
|
||||||
|
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
|
||||||
|
|
||||||
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
|
||||||
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
|
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
|
||||||
|
@ -266,6 +272,9 @@ struct psa_key_derivation_s
|
||||||
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
|
||||||
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
|
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
|
||||||
psa_tls12_prf_key_derivation_t MBEDTLS_PRIVATE(tls12_prf);
|
psa_tls12_prf_key_derivation_t MBEDTLS_PRIVATE(tls12_prf);
|
||||||
|
#endif
|
||||||
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
psa_tls12_ecjpake_to_pms_t MBEDTLS_PRIVATE(tls12_ecjpake_to_pms);
|
||||||
#endif
|
#endif
|
||||||
} MBEDTLS_PRIVATE(ctx);
|
} MBEDTLS_PRIVATE(ctx);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2021,6 +2021,14 @@
|
||||||
#define PSA_ALG_TLS12_PSK_TO_MS_GET_HASH(hkdf_alg) \
|
#define PSA_ALG_TLS12_PSK_TO_MS_GET_HASH(hkdf_alg) \
|
||||||
(PSA_ALG_CATEGORY_HASH | ((hkdf_alg) & PSA_ALG_HASH_MASK))
|
(PSA_ALG_CATEGORY_HASH | ((hkdf_alg) & PSA_ALG_HASH_MASK))
|
||||||
|
|
||||||
|
/* Macro to build a KDF that takes the shared secret K (an EC point in case
|
||||||
|
* of EC J-PAKE) and calculates SHA256(K.X) that the rest of TLS 1.2 will
|
||||||
|
* use to derive the session secret. Uses PSA_ALG_SHA_256.
|
||||||
|
*/
|
||||||
|
#define PSA_ALG_TLS12_ECJPAKE_TO_PMS ((psa_algorithm_t)0x08000600)
|
||||||
|
#define PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS(alg) \
|
||||||
|
(alg == PSA_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
|
||||||
/* This flag indicates whether the key derivation algorithm is suitable for
|
/* This flag indicates whether the key derivation algorithm is suitable for
|
||||||
* use on low-entropy secrets such as password - these algorithms are also
|
* use on low-entropy secrets such as password - these algorithms are also
|
||||||
* known as key stretching or password hashing schemes. These are also the
|
* known as key stretching or password hashing schemes. These are also the
|
||||||
|
|
|
@ -4243,7 +4243,8 @@ psa_status_t psa_aead_abort( psa_aead_operation_t *operation )
|
||||||
|
|
||||||
#if defined(BUILTIN_ALG_ANY_HKDF) || \
|
#if defined(BUILTIN_ALG_ANY_HKDF) || \
|
||||||
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
|
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) || \
|
||||||
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
|
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) || \
|
||||||
|
defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
#define AT_LEAST_ONE_BUILTIN_KDF
|
#define AT_LEAST_ONE_BUILTIN_KDF
|
||||||
#endif /* At least one builtin KDF */
|
#endif /* At least one builtin KDF */
|
||||||
|
|
||||||
|
@ -4350,6 +4351,14 @@ psa_status_t psa_key_derivation_abort( psa_key_derivation_operation_t *operation
|
||||||
else
|
else
|
||||||
#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) ||
|
#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF) ||
|
||||||
* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) */
|
* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS) */
|
||||||
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
if( PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
|
||||||
|
{
|
||||||
|
mbedtls_platform_zeroize( operation->ctx.tls12_ecjpake_to_pms.data,
|
||||||
|
PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS) */
|
||||||
{
|
{
|
||||||
status = PSA_ERROR_BAD_STATE;
|
status = PSA_ERROR_BAD_STATE;
|
||||||
}
|
}
|
||||||
|
@ -4631,6 +4640,31 @@ static psa_status_t psa_key_derivation_tls12_prf_read(
|
||||||
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF ||
|
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF ||
|
||||||
* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
|
* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
static psa_status_t psa_key_derivation_tls12_ecjpake_to_pms_read(
|
||||||
|
psa_tls12_ecjpake_to_pms_t *ecjpake,
|
||||||
|
uint8_t *output,
|
||||||
|
size_t output_length )
|
||||||
|
{
|
||||||
|
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
|
||||||
|
size_t output_size;
|
||||||
|
|
||||||
|
if( output_length != 32 )
|
||||||
|
return ( PSA_ERROR_INVALID_ARGUMENT );
|
||||||
|
|
||||||
|
status = psa_hash_compute( PSA_ALG_SHA_256, ecjpake->data,
|
||||||
|
PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE, output, output_length,
|
||||||
|
&output_size );
|
||||||
|
if( status != PSA_SUCCESS )
|
||||||
|
return ( status );
|
||||||
|
|
||||||
|
if( output_size != output_length )
|
||||||
|
return ( PSA_ERROR_GENERIC_ERROR );
|
||||||
|
|
||||||
|
return ( PSA_SUCCESS );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
psa_status_t psa_key_derivation_output_bytes(
|
psa_status_t psa_key_derivation_output_bytes(
|
||||||
psa_key_derivation_operation_t *operation,
|
psa_key_derivation_operation_t *operation,
|
||||||
uint8_t *output,
|
uint8_t *output,
|
||||||
|
@ -4685,6 +4719,15 @@ psa_status_t psa_key_derivation_output_bytes(
|
||||||
else
|
else
|
||||||
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF ||
|
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PRF ||
|
||||||
* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
|
* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
|
||||||
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
if( PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
|
||||||
|
{
|
||||||
|
status = psa_key_derivation_tls12_ecjpake_to_pms_read(
|
||||||
|
&operation->ctx.tls12_ecjpake_to_pms, output, output_length );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
|
||||||
|
|
||||||
{
|
{
|
||||||
(void) kdf_alg;
|
(void) kdf_alg;
|
||||||
return( PSA_ERROR_BAD_STATE );
|
return( PSA_ERROR_BAD_STATE );
|
||||||
|
@ -5076,6 +5119,10 @@ static int is_kdf_alg_supported( psa_algorithm_t kdf_alg )
|
||||||
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS)
|
||||||
if( PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) )
|
if( PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) )
|
||||||
return( 1 );
|
return( 1 );
|
||||||
|
#endif
|
||||||
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
if( PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
|
||||||
|
return( 1 );
|
||||||
#endif
|
#endif
|
||||||
return( 0 );
|
return( 0 );
|
||||||
}
|
}
|
||||||
|
@ -5100,19 +5147,26 @@ static psa_status_t psa_key_derivation_setup_kdf(
|
||||||
if( ! is_kdf_alg_supported( kdf_alg ) )
|
if( ! is_kdf_alg_supported( kdf_alg ) )
|
||||||
return( PSA_ERROR_NOT_SUPPORTED );
|
return( PSA_ERROR_NOT_SUPPORTED );
|
||||||
|
|
||||||
/* All currently supported key derivation algorithms are based on a
|
/* All currently supported key derivation algorithms (apart from
|
||||||
* hash algorithm. */
|
* ecjpake to pms are based on a hash algorithm. */
|
||||||
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg );
|
psa_algorithm_t hash_alg = PSA_ALG_HKDF_GET_HASH( kdf_alg );
|
||||||
size_t hash_size = PSA_HASH_LENGTH( hash_alg );
|
size_t hash_size = PSA_HASH_LENGTH( hash_alg );
|
||||||
if( hash_size == 0 )
|
if( !PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
|
||||||
return( PSA_ERROR_NOT_SUPPORTED );
|
{
|
||||||
|
if( hash_size == 0 )
|
||||||
|
return( PSA_ERROR_NOT_SUPPORTED );
|
||||||
|
|
||||||
/* Make sure that hash_alg is a supported hash algorithm. Otherwise
|
/* Make sure that hash_alg is a supported hash algorithm. Otherwise
|
||||||
* we might fail later, which is somewhat unfriendly and potentially
|
* we might fail later, which is somewhat unfriendly and potentially
|
||||||
* risk-prone. */
|
* risk-prone. */
|
||||||
psa_status_t status = psa_hash_try_support( hash_alg );
|
psa_status_t status = psa_hash_try_support( hash_alg );
|
||||||
if( status != PSA_SUCCESS )
|
if( status != PSA_SUCCESS )
|
||||||
return( status );
|
return( status );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
hash_size = PSA_HASH_LENGTH( PSA_ALG_SHA_256 );
|
||||||
|
}
|
||||||
|
|
||||||
if( ( PSA_ALG_IS_TLS12_PRF( kdf_alg ) ||
|
if( ( PSA_ALG_IS_TLS12_PRF( kdf_alg ) ||
|
||||||
PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) ) &&
|
PSA_ALG_IS_TLS12_PSK_TO_MS( kdf_alg ) ) &&
|
||||||
|
@ -5513,6 +5567,25 @@ static psa_status_t psa_tls12_prf_psk_to_ms_input(
|
||||||
}
|
}
|
||||||
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
|
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
static psa_status_t psa_tls12_ecjpake_to_pms_input(
|
||||||
|
psa_tls12_ecjpake_to_pms_t *ecjpake,
|
||||||
|
const uint8_t *data,
|
||||||
|
size_t data_length )
|
||||||
|
{
|
||||||
|
if( data_length != PSA_TLS12_ECJPAKE_TO_PMS_INPUT_SIZE )
|
||||||
|
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||||
|
|
||||||
|
/* Check if the passed point is in an uncompressed form */
|
||||||
|
if( data[0] != 0x04 )
|
||||||
|
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||||
|
|
||||||
|
/* Only K.X has to be extracted - bytes 1 to 32 inclusive. */
|
||||||
|
memcpy( ecjpake->data, data + 1, PSA_TLS12_ECJPAKE_TO_PMS_DATA_SIZE );
|
||||||
|
|
||||||
|
return( PSA_SUCCESS );
|
||||||
|
}
|
||||||
|
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
|
||||||
/** Check whether the given key type is acceptable for the given
|
/** Check whether the given key type is acceptable for the given
|
||||||
* input step of a key derivation.
|
* input step of a key derivation.
|
||||||
*
|
*
|
||||||
|
@ -5591,6 +5664,14 @@ static psa_status_t psa_key_derivation_input_internal(
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
|
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_PSK_TO_MS */
|
||||||
|
#if defined(MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS)
|
||||||
|
if( PSA_ALG_IS_TLS12_ECJPAKE_TO_PMS( kdf_alg ) )
|
||||||
|
{
|
||||||
|
status = psa_tls12_ecjpake_to_pms_input(
|
||||||
|
&operation->ctx.tls12_ecjpake_to_pms, data, data_length );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
#endif /* MBEDTLS_PSA_BUILTIN_ALG_TLS12_ECJPAKE_TO_PMS */
|
||||||
{
|
{
|
||||||
/* This can't happen unless the operation object was not initialized */
|
/* This can't happen unless the operation object was not initialized */
|
||||||
(void) data;
|
(void) data;
|
||||||
|
|
|
@ -357,6 +357,7 @@ class Algorithm:
|
||||||
'HKDF': AlgorithmCategory.KEY_DERIVATION,
|
'HKDF': AlgorithmCategory.KEY_DERIVATION,
|
||||||
'TLS12_PRF': AlgorithmCategory.KEY_DERIVATION,
|
'TLS12_PRF': AlgorithmCategory.KEY_DERIVATION,
|
||||||
'TLS12_PSK_TO_MS': AlgorithmCategory.KEY_DERIVATION,
|
'TLS12_PSK_TO_MS': AlgorithmCategory.KEY_DERIVATION,
|
||||||
|
'TLS12_ECJPAKE_TO_PMS': AlgorithmCategory.KEY_DERIVATION,
|
||||||
'PBKDF': AlgorithmCategory.KEY_DERIVATION,
|
'PBKDF': AlgorithmCategory.KEY_DERIVATION,
|
||||||
'ECDH': AlgorithmCategory.KEY_AGREEMENT,
|
'ECDH': AlgorithmCategory.KEY_AGREEMENT,
|
||||||
'FFDH': AlgorithmCategory.KEY_AGREEMENT,
|
'FFDH': AlgorithmCategory.KEY_AGREEMENT,
|
||||||
|
|
Loading…
Reference in a new issue