Skip to content

Commit 44d52b7

Browse files
authored
Add text encoder for ECC (#348)
* Add text encoder for ECC * Use whitespace insensitive check for public key print
1 parent 5140cc3 commit 44d52b7

File tree

6 files changed

+419
-0
lines changed

6 files changed

+419
-0
lines changed

include/wolfprovider/alg_funcs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,7 @@ extern const OSSL_DISPATCH wp_ecc_epki_der_encoder_functions[];
408408
extern const OSSL_DISPATCH wp_ecc_epki_pem_encoder_functions[];
409409
extern const OSSL_DISPATCH wp_ecc_x9_62_der_encoder_functions[];
410410
extern const OSSL_DISPATCH wp_ecc_x9_62_pem_encoder_functions[];
411+
extern const OSSL_DISPATCH wp_ecc_text_encoder_functions[];
411412
extern const OSSL_DISPATCH wp_x25519_spki_der_encoder_functions[];
412413
extern const OSSL_DISPATCH wp_x25519_spki_pem_encoder_functions[];
413414
extern const OSSL_DISPATCH wp_x25519_pki_der_encoder_functions[];

src/wp_ecc_kmgmt.c

Lines changed: 287 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2934,6 +2934,7 @@ static int wp_ecc_encode(wp_EccEncDecCtx* ctx, OSSL_CORE_BIO *cBio,
29342934
OPENSSL_free(pemData);
29352935
}
29362936
OPENSSL_free(cipherInfo);
2937+
BIO_free(out);
29372938
WOLFPROV_LEAVE(WP_LOG_COMP_ECC, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__), ok);
29382939
return ok;
29392940
}
@@ -3478,4 +3479,290 @@ const OSSL_DISPATCH wp_ecc_x9_62_pem_encoder_functions[] = {
34783479
{ 0, NULL }
34793480
};
34803481

3482+
/*
3483+
* ECC Text Encoder
3484+
*/
3485+
3486+
/**
3487+
* Create a new ECC text encoder context.
3488+
*
3489+
* @param [in] provCtx Provider context.
3490+
* @return New ECC encoder/decoder context object on success.
3491+
* @return NULL on failure.
3492+
*/
3493+
static wp_EccEncDecCtx* wp_ecc_text_enc_new(WOLFPROV_CTX* provCtx)
3494+
{
3495+
return wp_ecc_enc_dec_new(provCtx, WP_ENC_FORMAT_TEXT, WP_FORMAT_TEXT);
3496+
}
3497+
3498+
/**
3499+
* Return whether the ECC text encoder handles this part of the key.
3500+
*
3501+
* @param [in] provCtx Provider context. Unused.
3502+
* @param [in] selection Parts of key to handle.
3503+
* @return 1 when supported.
3504+
* @return 0 when not supported.
3505+
*/
3506+
static int wp_ecc_text_enc_does_selection(WOLFPROV_CTX* provCtx, int selection)
3507+
{
3508+
int ok;
3509+
3510+
(void)provCtx;
3511+
3512+
/* Text encoder supports both public and private key parts */
3513+
if (selection == 0) {
3514+
ok = 1;
3515+
}
3516+
else {
3517+
ok = ((selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0) ||
3518+
((selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0);
3519+
}
3520+
3521+
return ok;
3522+
}
3523+
3524+
/**
3525+
* Get the NIST curve name for the given curve ID.
3526+
*
3527+
* @param [in] curveId wolfSSL curve identifier.
3528+
* @return NIST curve name string on success.
3529+
* @return NULL if not a NIST curve.
3530+
*/
3531+
static const char* wp_ecc_get_nist_curve_name(int curveId)
3532+
{
3533+
const char* name = NULL;
3534+
3535+
switch (curveId) {
3536+
case ECC_SECP192R1:
3537+
name = "P-192";
3538+
break;
3539+
case ECC_SECP224R1:
3540+
name = "P-224";
3541+
break;
3542+
case ECC_SECP256R1:
3543+
name = "P-256";
3544+
break;
3545+
case ECC_SECP384R1:
3546+
name = "P-384";
3547+
break;
3548+
case ECC_SECP521R1:
3549+
name = "P-521";
3550+
break;
3551+
default:
3552+
break;
3553+
}
3554+
3555+
return name;
3556+
}
3557+
3558+
/** Number of bytes per line when printing labeled hex data (matches OpenSSL) */
3559+
#define WP_ECC_TEXT_PRINT_WIDTH 16
3560+
3561+
/**
3562+
* Print a labeled buffer in hex format matching OpenSSL's output.
3563+
*
3564+
* Format:
3565+
* label:
3566+
* xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:
3567+
* xx:xx:xx:xx:xx
3568+
*
3569+
* @param [in] out BIO to write output to.
3570+
* @param [in] label Label string to print before the hex data.
3571+
* @param [in] buf Buffer containing data to print.
3572+
* @param [in] bufLen Length of buffer in bytes.
3573+
* @return 1 on success.
3574+
* @return 0 on failure.
3575+
*/
3576+
static int wp_ecc_encode_text_labeled_buf(BIO* out, const char* label,
3577+
const unsigned char* buf, size_t bufLen)
3578+
{
3579+
int ok = 1;
3580+
size_t i;
3581+
3582+
if (BIO_printf(out, "%s\n", label) <= 0) {
3583+
ok = 0;
3584+
}
3585+
3586+
for (i = 0; ok && (i < bufLen); i++) {
3587+
if ((i % WP_ECC_TEXT_PRINT_WIDTH) == 0) {
3588+
if (i > 0 && BIO_printf(out, "\n") <= 0) {
3589+
ok = 0;
3590+
break;
3591+
}
3592+
if (BIO_printf(out, " ") <= 0) {
3593+
ok = 0;
3594+
break;
3595+
}
3596+
}
3597+
3598+
if (BIO_printf(out, "%02x%s", buf[i],
3599+
(i == bufLen - 1) ? "" : ":") <= 0) {
3600+
ok = 0;
3601+
break;
3602+
}
3603+
}
3604+
3605+
if (ok && BIO_printf(out, "\n") <= 0) {
3606+
ok = 0;
3607+
}
3608+
3609+
return ok;
3610+
}
3611+
3612+
/**
3613+
* Encode the ECC key in text format.
3614+
*
3615+
* @param [in] ctx ECC encoder/decoder context object.
3616+
* @param [in, out] cBio Core BIO to write data to.
3617+
* @param [in] key ECC key object.
3618+
* @param [in] params Key parameters. Unused.
3619+
* @param [in] selection Parts of key to encode.
3620+
* @param [in] pwCb Password callback. Unused.
3621+
* @param [in] pwCbArg Argument to pass to password callback. Unused.
3622+
* @return 1 on success.
3623+
* @return 0 on failure.
3624+
*/
3625+
static int wp_ecc_encode_text(wp_EccEncDecCtx* ctx, OSSL_CORE_BIO* cBio,
3626+
const wp_Ecc* key, const OSSL_PARAM* params, int selection,
3627+
OSSL_PASSPHRASE_CALLBACK* pwCb, void* pwCbArg)
3628+
{
3629+
int ok = 1;
3630+
BIO* out = wp_corebio_get_bio(ctx->provCtx, cBio);
3631+
int hasPriv = (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) != 0;
3632+
int hasPub = (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) != 0;
3633+
unsigned char* privBuf = NULL;
3634+
word32 privLen = 0;
3635+
unsigned char* pubBuf = NULL;
3636+
word32 pubLen = 0;
3637+
const char* curveName = NULL;
3638+
const char* nistName = NULL;
3639+
int rc;
3640+
3641+
WOLFPROV_ENTER(WP_LOG_COMP_ECC, "wp_ecc_encode_text");
3642+
3643+
(void)params;
3644+
(void)pwCb;
3645+
(void)pwCbArg;
3646+
3647+
if (!wolfssl_prov_is_running()) {
3648+
ok = 0;
3649+
}
3650+
3651+
if (ok && (out == NULL)) {
3652+
ok = 0;
3653+
}
3654+
3655+
/* Print header line */
3656+
if (ok) {
3657+
if (hasPriv) {
3658+
if (BIO_printf(out, "Private-Key: (%d bit)\n", key->bits) <= 0) {
3659+
ok = 0;
3660+
}
3661+
}
3662+
else if (hasPub) {
3663+
if (BIO_printf(out, "Public-Key: (%d bit)\n", key->bits) <= 0) {
3664+
ok = 0;
3665+
}
3666+
}
3667+
}
3668+
3669+
/* Export and print private key if present */
3670+
if (ok && hasPriv && key->hasPriv) {
3671+
mp_int* priv;
3672+
#if (!defined(HAVE_FIPS) || FIPS_VERSION_GE(5,3)) && \
3673+
LIBWOLFSSL_VERSION_HEX >= 0x05006002
3674+
priv = wc_ecc_key_get_priv((ecc_key*)&key->key);
3675+
#else
3676+
priv = (mp_int*)&key->key.k;
3677+
#endif
3678+
privLen = (word32)mp_unsigned_bin_size(priv);
3679+
if (privLen > 0) {
3680+
privBuf = (unsigned char*)OPENSSL_malloc(privLen);
3681+
if (privBuf == NULL) {
3682+
ok = 0;
3683+
}
3684+
else if (mp_to_unsigned_bin(priv, privBuf) != MP_OKAY) {
3685+
ok = 0;
3686+
}
3687+
else {
3688+
ok = wp_ecc_encode_text_labeled_buf(out, "priv:", privBuf,
3689+
privLen);
3690+
}
3691+
}
3692+
}
3693+
3694+
/* Export and print public key if present */
3695+
if (ok && (hasPriv || hasPub) && key->hasPub) {
3696+
/* Get size first */
3697+
PRIVATE_KEY_UNLOCK();
3698+
rc = wc_ecc_export_x963_ex((ecc_key*)&key->key, NULL, &pubLen, 0);
3699+
PRIVATE_KEY_LOCK();
3700+
if (rc != LENGTH_ONLY_E) {
3701+
ok = 0;
3702+
}
3703+
else {
3704+
pubBuf = (unsigned char*)OPENSSL_malloc(pubLen);
3705+
if (pubBuf == NULL) {
3706+
ok = 0;
3707+
}
3708+
else {
3709+
PRIVATE_KEY_UNLOCK();
3710+
rc = wc_ecc_export_x963_ex((ecc_key*)&key->key, pubBuf,
3711+
&pubLen, 0);
3712+
PRIVATE_KEY_LOCK();
3713+
if (rc != 0) {
3714+
ok = 0;
3715+
}
3716+
else {
3717+
ok = wp_ecc_encode_text_labeled_buf(out, "pub:", pubBuf,
3718+
pubLen);
3719+
}
3720+
}
3721+
}
3722+
}
3723+
3724+
/* Print ASN1 OID (curve short name) */
3725+
if (ok) {
3726+
curveName = wp_ecc_get_group_name((wp_Ecc*)key);
3727+
if (curveName != NULL) {
3728+
if (BIO_printf(out, "ASN1 OID: %s\n", curveName) <= 0) {
3729+
ok = 0;
3730+
}
3731+
}
3732+
}
3733+
3734+
/* Print NIST CURVE name if applicable */
3735+
if (ok) {
3736+
nistName = wp_ecc_get_nist_curve_name(key->curveId);
3737+
if (nistName != NULL) {
3738+
if (BIO_printf(out, "NIST CURVE: %s\n", nistName) <= 0) {
3739+
ok = 0;
3740+
}
3741+
}
3742+
}
3743+
3744+
/* Clean up */
3745+
if (privBuf != NULL) {
3746+
OPENSSL_clear_free(privBuf, privLen);
3747+
}
3748+
OPENSSL_free(pubBuf);
3749+
BIO_free(out);
3750+
3751+
WOLFPROV_LEAVE(WP_LOG_COMP_ECC, __FILE__ ":" WOLFPROV_STRINGIZE(__LINE__),
3752+
ok);
3753+
return ok;
3754+
}
3755+
3756+
/**
3757+
* Dispatch table for ECC text encoder.
3758+
*/
3759+
const OSSL_DISPATCH wp_ecc_text_encoder_functions[] = {
3760+
{ OSSL_FUNC_ENCODER_NEWCTX, (DFUNC)wp_ecc_text_enc_new },
3761+
{ OSSL_FUNC_ENCODER_FREECTX, (DFUNC)wp_ecc_enc_dec_free },
3762+
{ OSSL_FUNC_ENCODER_DOES_SELECTION,
3763+
(DFUNC)wp_ecc_text_enc_does_selection },
3764+
{ OSSL_FUNC_ENCODER_ENCODE, (DFUNC)wp_ecc_encode_text },
3765+
{ 0, NULL }
3766+
};
3767+
34813768
#endif /* WP_HAVE_ECC */

src/wp_wolfprov.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -828,6 +828,9 @@ static const OSSL_ALGORITHM wolfprov_encoder[] = {
828828
{ WP_NAMES_EC, WP_ENCODER_PROPERTIES(X9_62, pem),
829829
wp_ecc_x9_62_pem_encoder_functions,
830830
"" },
831+
{ WP_NAMES_EC, WP_ENCODER_PROPERTIES(type-specific, text),
832+
wp_ecc_text_encoder_functions,
833+
"" },
831834
#endif
832835

833836
#ifdef WP_HAVE_X25519

0 commit comments

Comments
 (0)