@@ -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 */
0 commit comments