@@ -469,7 +469,9 @@ static int wp_rsa_signverify_init(wp_RsaSigCtx* ctx, wp_Rsa* rsa,
469469 ctx -> saltLen = RSA_PSS_SALTLEN_AUTO ;
470470
471471 if (wp_rsa_get_type (ctx -> rsa ) == RSA_FLAG_TYPE_RSA ) {
472- ctx -> padMode = RSA_PKCS1_PADDING ;
472+ if (ctx -> padMode != RSA_X931_PADDING ) {
473+ ctx -> padMode = RSA_PKCS1_PADDING ;
474+ }
473475 }
474476 else {
475477 char * mdName ;
@@ -651,6 +653,56 @@ static int wp_rsa_sign_pss(wp_RsaSigCtx* ctx, unsigned char* sig,
651653 return ok ;
652654}
653655
656+ /**
657+ * Add X9.31 padding to the input buffer, placing the result in the output
658+ * buffer.
659+ *
660+ * @param to [out] Buffer to store padded result.
661+ * @param toLen [in] Length of "to" buffer.
662+ * @param from [in] Input buffer.
663+ * @param fromLen [in] Length of input buffer.
664+ * @returns 1 on success and 0 on failure.
665+ */
666+ static int wp_add_x931_padding (unsigned char * to , size_t toLen ,
667+ const unsigned char * from , size_t fromLen )
668+ {
669+ int ok = 1 ;
670+ int padBytes ;
671+
672+ if (to == NULL || from == NULL ) {
673+ WOLFPROV_ERROR_MSG (WP_LOG_PK , "Bad argument." );
674+ ok = 0 ;
675+ }
676+ else {
677+ /* Need at least two bytes for trailer and header. */
678+ padBytes = (int )(toLen - fromLen - 2 );
679+ if (padBytes < 0 ) {
680+ WOLFPROV_ERROR_MSG (WP_LOG_PK , "Output buffer too small." );
681+ ok = 0 ;
682+ }
683+ }
684+
685+ if (ok == 1 ) {
686+ if (padBytes == 0 ) {
687+ to [0 ] = 0x6A ;
688+ }
689+ else {
690+ to [0 ] = 0x6B ;
691+ if (padBytes > 1 ) {
692+ XMEMSET (& to [1 ], 0xBB , padBytes - 1 );
693+ }
694+ to [padBytes ] = 0xBA ;
695+ }
696+
697+ XMEMCPY (& to [padBytes + 1 ], from , fromLen );
698+ to [toLen - 1 ] = 0xCC ;
699+ }
700+
701+ WOLFPROV_LEAVE (WP_LOG_PK , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
702+
703+ return ok ;
704+ }
705+
654706/**
655707 * Sign the data using RSA without padding.
656708 *
@@ -691,6 +743,134 @@ static int wp_rsa_sign_no_pad(wp_RsaSigCtx* ctx, unsigned char* sig,
691743 return ok ;
692744}
693745
746+ static int wp_rsa_get_x931_hash_code (enum wc_HashType hash ) {
747+ int ret = 0 ;
748+
749+ if (hash == WC_HASH_TYPE_SHA ) {
750+ ret = 0x33 ;
751+ }
752+ else if (hash == WC_HASH_TYPE_SHA256 ) {
753+ ret = 0x34 ;
754+ }
755+ else if (hash == WC_HASH_TYPE_SHA384 ) {
756+ ret = 0x36 ;
757+ }
758+ else if (hash == WC_HASH_TYPE_SHA512 ) {
759+ ret = 0x35 ;
760+ }
761+
762+ return ret ;
763+ }
764+
765+ /**
766+ * Sign the data using RSA with X931 padding.
767+ *
768+ * @param [in, out] ctx RSA signature context object.
769+ * @param [out] sig Buffer to hold signature.
770+ * @param [out] sigLen Length of signature data in bytes.
771+ * @param [in] sigSize Size of signature buffer in bytes.
772+ * @param [in] tbs Data to be signed.
773+ * @param [in] tbsLen Length of data to be signed in bytes.
774+ * @return 1 on success.
775+ * @return 0 on failure.
776+ */
777+ static int wp_rsa_sign_x931 (wp_RsaSigCtx * ctx , unsigned char * sig ,
778+ size_t * sigLen , size_t sigSize , const unsigned char * tbs , size_t tbsLen )
779+ {
780+ int ok = 1 ;
781+ int paddedSz = 0 ;
782+ unsigned char * padded = NULL ;
783+ unsigned char * tbuf = NULL ;
784+ int rc = 0 ;
785+ mp_int toMp ;
786+ mp_int nMinusTo ;
787+
788+ paddedSz = wc_RsaEncryptSize (wp_rsa_get_key (ctx -> rsa ));
789+ if (paddedSz <= 0 ) {
790+ ok = 0 ;
791+ }
792+ if (ok ) {
793+ tbuf = (unsigned char * )OPENSSL_malloc (paddedSz );
794+ if (tbuf == NULL ) {
795+ ok = 0 ;
796+ }
797+ }
798+ if (ok ) {
799+ padded = (unsigned char * )OPENSSL_malloc (paddedSz );
800+ if (padded == NULL ) {
801+ ok = 0 ;
802+ }
803+ }
804+ if (ok ) {
805+ XMEMCPY (tbuf , tbs , tbsLen );
806+ tbuf [tbsLen ] = wp_rsa_get_x931_hash_code (
807+ #if LIBWOLFSSL_VERSION_HEX >= 0x05007004
808+ ctx -> hash .type
809+ #else
810+ ctx -> hashType
811+ #endif
812+ );
813+ }
814+ if (ok ) {
815+ if (wp_add_x931_padding (padded , paddedSz , tbuf , tbsLen + 1 ) != 1 ) {
816+ ok = 0 ;
817+ }
818+ }
819+ if (ok ) {
820+ word32 len = (word32 )sigSize ;
821+
822+ PRIVATE_KEY_UNLOCK ();
823+ rc = wc_RsaDirect (padded , paddedSz , sig , & len ,
824+ wp_rsa_get_key (ctx -> rsa ), RSA_PRIVATE_ENCRYPT , & ctx -> rng );
825+ PRIVATE_KEY_LOCK ();
826+ if (rc < 0 ) {
827+ ok = 0 ;
828+ }
829+ else {
830+ * sigLen = rc ;
831+ }
832+ }
833+ if (padded != NULL ) {
834+ OPENSSL_free (padded );
835+ }
836+ if (tbuf != NULL ) {
837+ OPENSSL_free (tbuf );
838+ }
839+ if (ok ) {
840+ rc = mp_init_multi (& toMp , & nMinusTo , NULL , NULL , NULL , NULL );
841+ if (rc != MP_OKAY ) {
842+ ok = 0 ;
843+ }
844+ }
845+ if (ok ) {
846+ rc = mp_read_unsigned_bin (& toMp , sig , * sigLen );
847+ if (rc != MP_OKAY ) {
848+ ok = 0 ;
849+ }
850+ }
851+ if (ok ) {
852+ /*
853+ * X9.31 specifies, "The signature is either the result
854+ * or its complement to n, whichever is smaller."
855+ */
856+ rc = mp_sub (& (wp_rsa_get_key (ctx -> rsa )-> n ), & toMp , & nMinusTo );
857+ if (rc != MP_OKAY ) {
858+ ok = 0 ;
859+ }
860+ else if (mp_cmp (& toMp , & nMinusTo ) == MP_GT ) {
861+ rc = mp_to_unsigned_bin (& nMinusTo , sig );
862+ if (rc != MP_OKAY ) {
863+ ok = 0 ;
864+ }
865+ }
866+ }
867+ mp_free (& toMp );
868+ mp_free (& nMinusTo );
869+
870+ WOLFPROV_LEAVE (WP_LOG_PK , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
871+ return ok ;
872+ }
873+
694874/**
695875 * Sign the data using an RSA key.
696876 *
@@ -733,6 +913,9 @@ static int wp_rsa_sign(wp_RsaSigCtx* ctx, unsigned char* sig, size_t* sigLen,
733913 else if (ctx -> padMode == RSA_NO_PADDING ) {
734914 ok = wp_rsa_sign_no_pad (ctx , sig , sigLen , sigSize , tbs , tbsLen );
735915 }
916+ else if (ctx -> padMode == RSA_X931_PADDING ) {
917+ ok = wp_rsa_sign_x931 (ctx , sig , sigLen , sigSize , tbs , tbsLen );
918+ }
736919 else {
737920 ok = 0 ;
738921 }
@@ -929,6 +1112,163 @@ static int wp_rsa_verify_no_pad(wp_RsaSigCtx* ctx, const unsigned char* sig,
9291112 return ok ;
9301113}
9311114
1115+ /**
1116+ * Remove X9.31 padding from the input buffer, placing the result in the output
1117+ * buffer.
1118+ *
1119+ * @param to [out] Pointer to buffer holding unpadded result. This
1120+ * buffer will be allocated by this function if *to is
1121+ * NULL.
1122+ * @param from [in] Input buffer.
1123+ * @param fromLen [in] Length of input buffer.
1124+ * @returns Length of unpadded result on success and -1 on failure.
1125+ */
1126+ static int wp_remove_x931_padding (unsigned char * * to , const unsigned char * from ,
1127+ size_t fromLen )
1128+ {
1129+ int ret = -1 ;
1130+ int ok = 1 ;
1131+ size_t idx = 0 ;
1132+ size_t numCopy = 0 ;
1133+
1134+ if (to == NULL || from == NULL || fromLen < 2 ) {
1135+ ok = 0 ;
1136+ }
1137+ else {
1138+ if (from [fromLen - 1 ] != 0xCC ) {
1139+ ok = 0 ;
1140+ }
1141+
1142+ if (from [idx ] == 0x6B ) {
1143+ while (++ idx < fromLen && from [idx ] == 0xBB ) {}
1144+
1145+ if (idx == fromLen || from [idx ] != 0xBA ) {
1146+ ok = 0 ;
1147+ }
1148+ }
1149+ else if (from [idx ] != 0x6A ) {
1150+ ok = 0 ;
1151+ }
1152+ }
1153+
1154+ if (ok ) {
1155+ ++ idx ;
1156+ numCopy = fromLen - idx - 1 ;
1157+ if (numCopy > 0 ) {
1158+ if (* to == NULL ) {
1159+ * to = (unsigned char * )OPENSSL_malloc (numCopy );
1160+ if (* to == NULL ) {
1161+ ok = 0 ;
1162+ }
1163+ }
1164+ if (ok ){
1165+ XMEMCPY (* to , from + idx , numCopy );
1166+ }
1167+ }
1168+ }
1169+
1170+ if (ok ) {
1171+ ret = (int )numCopy ;
1172+ }
1173+
1174+ WOLFPROV_LEAVE (WP_LOG_PK , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ret );
1175+ return ret ;
1176+ }
1177+
1178+ /**
1179+ * Verify an RSA X931 padded signature.
1180+ *
1181+ * @param [in] ctx RSA signature context object.
1182+ * @param [in] sig Signature data.
1183+ * @param [in] sigLen Length of signature data in bytes.
1184+ * @param [in] tbs Data to be signed.
1185+ * @param [in] tbsLen Length of data to be signed in bytes.
1186+ * @param [in] decryptedSig Buffer to hold decrypted signature.
1187+ * @return 1 on success.
1188+ * @return 0 on failure.
1189+ */
1190+ static int wp_rsa_verify_x931 (wp_RsaSigCtx * ctx , const unsigned char * sig ,
1191+ size_t sigLen , const unsigned char * tbs , size_t tbsLen ,
1192+ unsigned char * decryptedSig )
1193+ {
1194+ int ok = 1 ;
1195+ int rc ;
1196+ word32 len = (word32 )sigLen ;
1197+ unsigned char * unpadded = NULL ;
1198+ mp_int toMp ;
1199+ mp_int nMinusTo ;
1200+
1201+ rc = wc_RsaDirect ((byte * )sig , (word32 )sigLen , decryptedSig , & len ,
1202+ wp_rsa_get_key (ctx -> rsa ), RSA_PUBLIC_DECRYPT , & ctx -> rng );
1203+ if (rc < 0 ) {
1204+ ok = 0 ;
1205+ }
1206+ if (ok ) {
1207+ /*
1208+ * X9.31 specifies, "If e is odd, then
1209+ * - If RR = 12 mod 16, then IR = RR ;
1210+ * - If n - RR = 12 mod 16, then IR = n - RR ;"
1211+ * RR is "to" and IR is the value to unpad in the next
1212+ * step. Taking "to" mod 16 is the same as just checking the
1213+ * lower 4 bits of "to."
1214+ */
1215+ if ((decryptedSig [sigLen - 1 ] & 0x0F ) != 12 ) {
1216+ rc = mp_init_multi (& toMp , & nMinusTo , NULL , NULL , NULL , NULL );
1217+ if (rc != MP_OKAY ) {
1218+ ok = 0 ;
1219+ }
1220+ if (ok ) {
1221+ rc = mp_read_unsigned_bin (& toMp , decryptedSig , (int )sigLen );
1222+ if (rc != MP_OKAY ) {
1223+ ok = 0 ;
1224+ } else {
1225+ rc = mp_sub (& (wp_rsa_get_key (ctx -> rsa )-> n ), & toMp , & nMinusTo );
1226+ if (rc != MP_OKAY ) {
1227+ ok = 0 ;
1228+ } else {
1229+ rc = mp_to_unsigned_bin (& nMinusTo , decryptedSig );
1230+ if (rc != MP_OKAY ) {
1231+ ok = 0 ;
1232+ }
1233+ }
1234+ }
1235+ }
1236+ mp_free (& toMp );
1237+ mp_free (& nMinusTo );
1238+ }
1239+ }
1240+ if (ok ) {
1241+ rc = wp_remove_x931_padding (& unpadded , decryptedSig , len );
1242+ if (rc <= 0 ) {
1243+ ok = 0 ;
1244+ } else {
1245+ XMEMCPY (decryptedSig , unpadded , rc );
1246+ rc -- ;
1247+ }
1248+ }
1249+ if (ok ) {
1250+ if (unpadded [rc ] != wp_rsa_get_x931_hash_code (
1251+ #if LIBWOLFSSL_VERSION_HEX >= 0x05007004
1252+ ctx -> hash .type
1253+ #else
1254+ ctx -> hashType
1255+ #endif
1256+ )) {
1257+ ok = 0 ;
1258+ }
1259+ }
1260+ if (ok && (((size_t )rc != tbsLen ) || ((XMEMCMP (tbs , decryptedSig ,
1261+ tbsLen ) != 0 )))) {
1262+ ok = 0 ;
1263+ }
1264+ if (NULL != unpadded ) {
1265+ OPENSSL_free (unpadded );
1266+ }
1267+
1268+ WOLFPROV_LEAVE (WP_LOG_PK , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ), ok );
1269+ return ok ;
1270+ }
1271+
9321272/**
9331273 * Verify an RSA signature.
9341274 *
@@ -970,6 +1310,10 @@ static int wp_rsa_verify(wp_RsaSigCtx* ctx, const unsigned char* sig,
9701310 ok = wp_rsa_verify_no_pad (ctx , sig , sigLen , tbs , tbsLen ,
9711311 decryptedSig );
9721312 }
1313+ else if (ctx -> padMode == RSA_X931_PADDING ) {
1314+ ok = wp_rsa_verify_x931 (ctx , sig , sigLen , tbs , tbsLen ,
1315+ decryptedSig );
1316+ }
9731317 else {
9741318 ok = 0 ;
9751319 }
@@ -1517,6 +1861,11 @@ static int wp_rsa_set_pad_mode(wp_RsaSigCtx* ctx, const OSSL_PARAM* p)
15171861 ok = 0 ;
15181862 }
15191863 }
1864+ else if (padMode == RSA_X931_PADDING ) {
1865+ if (wp_rsa_get_type (ctx -> rsa ) != RSA_FLAG_TYPE_RSA ) {
1866+ ok = 0 ;
1867+ }
1868+ }
15201869 else {
15211870 ok = 0 ;
15221871 }
0 commit comments