@@ -2819,3 +2819,360 @@ int test_wc_FreeRsaKey_CryptoCb(void)
28192819#endif
28202820 return EXPECT_RESULT ();
28212821}
2822+
2823+ /* WOLFSSL_NO_RSA_SW_PAD is derived inside rsa.c, so check WOLFSSL_NO_RSA_SW:
2824+ * these tests need the software OAEP and raw RSA paths. */
2825+ #if !defined(NO_RSA ) && !defined(WC_NO_RSA_OAEP ) && \
2826+ !defined(WOLFSSL_NO_RSA_SW ) && !defined(NO_HASH_WRAPPER ) && \
2827+ !defined(NO_SHA256 ) && !defined(WOLFSSL_RSA_VERIFY_ONLY ) && \
2828+ !defined(HAVE_FIPS ) && !defined(HAVE_SELFTEST )
2829+ #define TEST_RSA_OAEP_CRAFT
2830+ #define TEST_RSA_OAEP_HLEN WC_SHA256_DIGEST_SIZE
2831+
2832+ /* The vectors are 2048-bit blocks. Unpadding works in a scratch buffer sized
2833+ * for RSA_MAX_SIZE, so skip when the build can't hold a 2048-bit block. */
2834+ #if RSA_MAX_SIZE >= 2048
2835+ #define TEST_RSA_OAEP_SEPARATOR
2836+ #endif
2837+ /* Key generation and the raw RSA operation need software RSA, or with
2838+ * callback-only RSA, the wc_swdev device to do them. */
2839+ #if defined(WOLFSSL_KEY_GEN ) && !defined(WC_NO_RNG ) && \
2840+ !defined(WOLFSSL_RSA_PUBLIC_ONLY ) && \
2841+ (!defined(WOLF_CRYPTO_CB_ONLY_RSA ) || defined(WOLFSSL_SWDEV ))
2842+ #define TEST_RSA_OAEP_ZEROLEN
2843+ #endif
2844+ #endif /* TEST_RSA_OAEP_CRAFT conditions */
2845+
2846+ /* Only compile the helpers when a test uses them. */
2847+ #if defined(TEST_RSA_OAEP_SEPARATOR ) || defined(TEST_RSA_OAEP_ZEROLEN )
2848+
2849+ /* MGF1 with SHA-256 (RFC 8017, B.2.1), written independently of the library
2850+ * so that hand-built encoded messages don't depend on the code under test. */
2851+ static int rsa_oaep_test_mgf1 (const byte * seed , word32 seedLen , byte * out ,
2852+ word32 outLen )
2853+ {
2854+ byte buf [512 + 4 ];
2855+ byte h [TEST_RSA_OAEP_HLEN ];
2856+ word32 cnt ;
2857+ word32 o = 0 ;
2858+ word32 n ;
2859+ int ret = 0 ;
2860+
2861+ if (seedLen > 512 )
2862+ return BAD_FUNC_ARG ;
2863+ XMEMCPY (buf , seed , seedLen );
2864+ for (cnt = 0 ; (ret == 0 ) && (o < outLen ); cnt ++ ) {
2865+ buf [seedLen + 0 ] = (byte )(cnt >> 24 );
2866+ buf [seedLen + 1 ] = (byte )(cnt >> 16 );
2867+ buf [seedLen + 2 ] = (byte )(cnt >> 8 );
2868+ buf [seedLen + 3 ] = (byte )cnt ;
2869+ ret = wc_Sha256Hash (buf , seedLen + 4 , h );
2870+ n = outLen - o ;
2871+ if (n > TEST_RSA_OAEP_HLEN )
2872+ n = TEST_RSA_OAEP_HLEN ;
2873+ if (ret == 0 )
2874+ XMEMCPY (out + o , h , n );
2875+ o += n ;
2876+ }
2877+ return ret ;
2878+ }
2879+
2880+ /* Build an OAEP-SHA256 encoded message Y | maskedSeed | maskedDB from a
2881+ * caller-chosen DB, so that malformed DBs can be produced.
2882+ * db is blockLen - hLen - 1 bytes. */
2883+ static int rsa_oaep_test_encode (const byte * db , byte * block , word32 blockLen ,
2884+ byte y )
2885+ {
2886+ byte seed [TEST_RSA_OAEP_HLEN ];
2887+ byte mask [512 ];
2888+ word32 dbLen = blockLen - TEST_RSA_OAEP_HLEN - 1 ;
2889+ word32 i ;
2890+ int ret ;
2891+
2892+ if (blockLen > sizeof (mask ))
2893+ return BAD_FUNC_ARG ;
2894+ XMEMSET (seed , 0x3c , sizeof (seed ));
2895+ block [0 ] = y ;
2896+ ret = rsa_oaep_test_mgf1 (seed , TEST_RSA_OAEP_HLEN , mask , dbLen );
2897+ for (i = 0 ; (ret == 0 ) && (i < dbLen ); i ++ )
2898+ block [1 + TEST_RSA_OAEP_HLEN + i ] = db [i ] ^ mask [i ];
2899+ if (ret == 0 ) {
2900+ ret = rsa_oaep_test_mgf1 (block + 1 + TEST_RSA_OAEP_HLEN , dbLen , mask ,
2901+ TEST_RSA_OAEP_HLEN );
2902+ }
2903+ for (i = 0 ; (ret == 0 ) && (i < TEST_RSA_OAEP_HLEN ); i ++ )
2904+ block [1 + i ] = seed [i ] ^ mask [i ];
2905+ return ret ;
2906+ }
2907+
2908+ /* Fill DB as lHash | zeros, then place the separator byte at offset sepOff
2909+ * of DB (sepOff == 0 means no byte is placed) and the message after it. */
2910+ static void rsa_oaep_test_db (byte * db , word32 dbLen , const byte * lHash ,
2911+ word32 sepOff , byte sepByte , const byte * msg )
2912+ {
2913+ XMEMSET (db , 0 , dbLen );
2914+ XMEMCPY (db , lHash , TEST_RSA_OAEP_HLEN );
2915+ if (sepOff != 0 ) {
2916+ db [sepOff ] = sepByte ;
2917+ XMEMCPY (db + sepOff + 1 , msg , dbLen - sepOff - 1 );
2918+ }
2919+ }
2920+ #endif /* TEST_RSA_OAEP_SEPARATOR || TEST_RSA_OAEP_ZEROLEN */
2921+
2922+ /*
2923+ * Testing that OAEP unpadding finds the separator at every position and
2924+ * rejects malformed padding with a zero length and an end-of-block pointer.
2925+ */
2926+ int test_wc_RsaUnPad_OaepSeparator (void )
2927+ {
2928+ EXPECT_DECLS ;
2929+ #ifdef TEST_RSA_OAEP_SEPARATOR
2930+ /* 2048-bit block. DB is lHash (32) | PS | 0x01 | M, from offset 33. */
2931+ enum {
2932+ BLK = 256 ,
2933+ HL = TEST_RSA_OAEP_HLEN ,
2934+ DBLEN = BLK - HL - 1 ,
2935+ DBOFF = HL + 1
2936+ };
2937+ byte label [] = { 'l' , 'a' , 'b' , 'e' , 'l' };
2938+ byte badLabel [] = { 'l' , 'a' , 'b' , 'e' , 'L' };
2939+ byte lHash [HL ];
2940+ byte lHashLabel [HL ];
2941+ byte msg [DBLEN ];
2942+ byte db [DBLEN ];
2943+ byte block [BLK ];
2944+ byte * out ;
2945+ word32 sepOff ;
2946+ word32 i ;
2947+ int ret ;
2948+
2949+ ExpectIntEQ (wc_Sha256Hash (NULL , 0 , lHash ), 0 );
2950+ ExpectIntEQ (wc_Sha256Hash (label , sizeof (label ), lHashLabel ), 0 );
2951+
2952+ /* Message with zero bytes and extra 0x01 bytes, including at its start, so
2953+ * only the first non-zero byte after lHash may be taken as separator. */
2954+ for (i = 0 ; i < DBLEN ; i ++ )
2955+ msg [i ] = (byte )(((i % 3 ) == 0 ) ? 0x00 : (((i % 3 ) == 1 ) ? 0x01 : i ));
2956+
2957+ /* Separator at every position, from right after lHash (PS empty, longest
2958+ * message) to the last byte of the block (empty message). */
2959+ for (sepOff = HL ; EXPECT_SUCCESS () && (sepOff < DBLEN ); sepOff ++ ) {
2960+ word32 mLen = DBLEN - sepOff - 1 ;
2961+
2962+ rsa_oaep_test_db (db , DBLEN , lHash , sepOff , 0x01 , msg );
2963+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x00 ), 0 );
2964+ out = NULL ;
2965+ ret = wc_RsaUnPad_ex (block , BLK , & out , RSA_BLOCK_TYPE_2 ,
2966+ WC_RSA_OAEP_PAD , WC_HASH_TYPE_SHA256 , WC_MGF1SHA256 , NULL , 0 , 0 ,
2967+ BLK * 8 , HEAP_HINT );
2968+ ExpectIntEQ (ret , (int )mLen );
2969+ ExpectPtrEq (out , block + BLK - mLen );
2970+ if (mLen > 0 ) {
2971+ ExpectBufEQ (out , msg , mLen );
2972+ }
2973+ }
2974+
2975+ /* Same encoding with a matching non-empty label. */
2976+ rsa_oaep_test_db (db , DBLEN , lHashLabel , 100 , 0x01 , msg );
2977+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x00 ), 0 );
2978+ out = NULL ;
2979+ ExpectIntEQ (wc_RsaUnPad_ex (block , BLK , & out , RSA_BLOCK_TYPE_2 ,
2980+ WC_RSA_OAEP_PAD , WC_HASH_TYPE_SHA256 , WC_MGF1SHA256 , label ,
2981+ sizeof (label ), 0 , BLK * 8 , HEAP_HINT ), DBLEN - 101 );
2982+ ExpectPtrEq (out , block + DBOFF + 101 );
2983+ ExpectBufEQ (out , msg , DBLEN - 101 );
2984+
2985+ /* Each malformed block must give length 0 and a pointer to the end of the
2986+ * block, the same as each other, so the failures look alike. Unpadding
2987+ * demasks the block in place, so each case encodes it again. */
2988+ #define TEST_OAEP_BAD (lbl , lblLen ) do { \
2989+ out = NULL; \
2990+ ExpectIntEQ(wc_RsaUnPad_ex(block, BLK, &out, RSA_BLOCK_TYPE_2, \
2991+ WC_RSA_OAEP_PAD, WC_HASH_TYPE_SHA256, WC_MGF1SHA256, (lbl), \
2992+ (lblLen), 0, BLK * 8, HEAP_HINT), 0); \
2993+ ExpectPtrEq(out, block + BLK); \
2994+ } while (0)
2995+
2996+ /* No separator: only zeros after lHash. */
2997+ rsa_oaep_test_db (db , DBLEN , lHash , 0 , 0 , NULL );
2998+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x00 ), 0 );
2999+ TEST_OAEP_BAD (NULL , 0 );
3000+
3001+ /* First non-zero byte is not 0x01, with a 0x01 right after it and at the
3002+ * last byte - neither may be taken as the separator. */
3003+ for (i = 0 ; i < 3 ; i ++ ) {
3004+ static const byte badSep [3 ] = { 0x02 , 0x80 , 0xff };
3005+
3006+ rsa_oaep_test_db (db , DBLEN , lHash , 100 , badSep [i ], msg );
3007+ db [101 ] = 0x01 ;
3008+ db [DBLEN - 1 ] = 0x01 ;
3009+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x00 ), 0 );
3010+ TEST_OAEP_BAD (NULL , 0 );
3011+ }
3012+
3013+ /* Invalid first byte of the last position: 0x02 instead of 0x01. */
3014+ rsa_oaep_test_db (db , DBLEN , lHash , DBLEN - 1 , 0x02 , msg );
3015+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x00 ), 0 );
3016+ TEST_OAEP_BAD (NULL , 0 );
3017+
3018+ /* Valid separator at the first and last positions, but Y is not zero. */
3019+ rsa_oaep_test_db (db , DBLEN , lHash , HL , 0x01 , msg );
3020+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x01 ), 0 );
3021+ TEST_OAEP_BAD (NULL , 0 );
3022+ rsa_oaep_test_db (db , DBLEN , lHash , DBLEN - 1 , 0x01 , msg );
3023+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x80 ), 0 );
3024+ TEST_OAEP_BAD (NULL , 0 );
3025+
3026+ /* Valid separator but lHash does not match: one bit flipped, and a block
3027+ * encoded for a label but decoded with none or with another label. */
3028+ rsa_oaep_test_db (db , DBLEN , lHash , 100 , 0x01 , msg );
3029+ db [HL - 1 ] ^= 0x01 ;
3030+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x00 ), 0 );
3031+ TEST_OAEP_BAD (NULL , 0 );
3032+ rsa_oaep_test_db (db , DBLEN , lHashLabel , 100 , 0x01 , msg );
3033+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x00 ), 0 );
3034+ TEST_OAEP_BAD (NULL , 0 );
3035+ /* Unpadding demasks in place, so encode again before each attempt. */
3036+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x00 ), 0 );
3037+ TEST_OAEP_BAD (badLabel , sizeof (badLabel ));
3038+ #undef TEST_OAEP_BAD
3039+ #else
3040+ return TEST_SKIPPED ;
3041+ #endif /* TEST_RSA_OAEP_SEPARATOR */
3042+ return EXPECT_RESULT ();
3043+ }
3044+
3045+ /*
3046+ * Testing the length RSA-OAEP private decrypt returns for an empty message
3047+ * and for invalid padding: 0 with WOLFSSL_RSA_DECRYPT_TO_0_LEN, otherwise
3048+ * RSA_BUFFER_E. In both builds the two cases must give the same result.
3049+ */
3050+ int test_wc_RsaPrivateDecrypt_OaepZeroLen (void )
3051+ {
3052+ EXPECT_DECLS ;
3053+ #ifdef TEST_RSA_OAEP_ZEROLEN
3054+ enum {
3055+ BLK = TEST_RSA_BYTES ,
3056+ HL = TEST_RSA_OAEP_HLEN ,
3057+ DBLEN = BLK - HL - 1
3058+ };
3059+ RsaKey key ;
3060+ WC_RNG rng ;
3061+ byte lHash [HL ];
3062+ byte msg [DBLEN ];
3063+ byte db [DBLEN ];
3064+ byte block [BLK ];
3065+ byte cipher [BLK ];
3066+ byte plain [BLK ];
3067+ byte * outPtr ;
3068+ word32 cipherLen ;
3069+ int i ;
3070+ #ifdef WOLFSSL_RSA_DECRYPT_TO_0_LEN
3071+ const int zeroRet = 0 ;
3072+ #else
3073+ const int zeroRet = WC_NO_ERR_TRACE (RSA_BUFFER_E );
3074+ #endif
3075+
3076+ XMEMSET (& key , 0 , sizeof (key ));
3077+ XMEMSET (& rng , 0 , sizeof (rng ));
3078+ XMEMSET (msg , 0x5a , sizeof (msg ));
3079+ ExpectIntEQ (wc_InitRsaKey (& key , HEAP_HINT ), 0 );
3080+ ExpectIntEQ (wc_InitRng (& rng ), 0 );
3081+ ExpectIntEQ (MAKE_RSA_KEY (& key , TEST_RSA_BITS , WC_RSA_EXPONENT , & rng ), 0 );
3082+ #ifdef WC_RSA_BLINDING
3083+ ExpectIntEQ (wc_RsaSetRNG (& key , & rng ), 0 );
3084+ #endif
3085+ ExpectIntEQ (wc_Sha256Hash (NULL , 0 , lHash ), 0 );
3086+
3087+ /* 0: empty message (separator in the last byte), 1: no separator,
3088+ * 2: invalid separator byte, 3: non-empty message as a control. */
3089+ for (i = 0 ; i < 4 ; i ++ ) {
3090+ if (i == 0 )
3091+ rsa_oaep_test_db (db , DBLEN , lHash , DBLEN - 1 , 0x01 , msg );
3092+ else if (i == 1 )
3093+ rsa_oaep_test_db (db , DBLEN , lHash , 0 , 0 , NULL );
3094+ else if (i == 2 )
3095+ rsa_oaep_test_db (db , DBLEN , lHash , DBLEN - 9 , 0x02 , msg );
3096+ else
3097+ rsa_oaep_test_db (db , DBLEN , lHash , DBLEN - 9 , 0x01 , msg );
3098+ ExpectIntEQ (rsa_oaep_test_encode (db , block , BLK , 0x00 ), 0 );
3099+ /* Raw RSA public operation: the public encrypt API rejects an empty
3100+ * message and only produces valid padding. */
3101+ cipherLen = sizeof (cipher );
3102+ ExpectIntEQ (wc_RsaFunction (block , BLK , cipher , & cipherLen ,
3103+ RSA_PUBLIC_ENCRYPT , & key , & rng ), 0 );
3104+ ExpectIntEQ (cipherLen , BLK );
3105+
3106+ XMEMSET (plain , 0xa5 , sizeof (plain ));
3107+ ExpectIntEQ (wc_RsaPrivateDecrypt_ex (cipher , cipherLen , plain ,
3108+ sizeof (plain ), & key , WC_RSA_OAEP_PAD , WC_HASH_TYPE_SHA256 ,
3109+ WC_MGF1SHA256 , NULL , 0 ), (i == 3 ) ? 8 : zeroRet );
3110+ if (i == 3 ) {
3111+ ExpectBufEQ (plain , msg , 8 );
3112+ }
3113+
3114+ outPtr = NULL ;
3115+ ExpectIntEQ (wc_RsaPrivateDecryptInline_ex (cipher , cipherLen , & outPtr ,
3116+ & key , WC_RSA_OAEP_PAD , WC_HASH_TYPE_SHA256 , WC_MGF1SHA256 , NULL ,
3117+ 0 ), (i == 3 ) ? 8 : zeroRet );
3118+ if (i == 3 ) {
3119+ ExpectPtrEq (outPtr , cipher + BLK - 8 );
3120+ ExpectBufEQ (outPtr , msg , 8 );
3121+ }
3122+ }
3123+
3124+ DoExpectIntEQ (wc_FreeRsaKey (& key ), 0 );
3125+ DoExpectIntEQ (wc_FreeRng (& rng ), 0 );
3126+ #else
3127+ return TEST_SKIPPED ;
3128+ #endif
3129+ return EXPECT_RESULT ();
3130+ }
3131+
3132+ /*
3133+ * Testing that OAEP unpadding accepts a block of RSA_MAX_SIZE bits, and that a
3134+ * longer block is rejected when the scratch buffer is on stack instead of
3135+ * overrunning it, and is handled when the scratch buffer is allocated.
3136+ */
3137+ int test_wc_RsaUnPad_OaepBlockLen (void )
3138+ {
3139+ EXPECT_DECLS ;
3140+ #ifdef TEST_RSA_OAEP_CRAFT
3141+ const word32 maxLen = RSA_MAX_SIZE / 8 ;
3142+ byte * block = NULL ;
3143+ byte * out ;
3144+
3145+ ExpectNotNull (block = (byte * )XMALLOC (maxLen + 1 , HEAP_HINT ,
3146+ DYNAMIC_TYPE_TMP_BUFFER ));
3147+ if (block != NULL ) {
3148+ /* Largest block: processed, and all zeros is invalid padding. */
3149+ XMEMSET (block , 0 , maxLen + 1 );
3150+ out = NULL ;
3151+ ExpectIntEQ (wc_RsaUnPad_ex (block , maxLen , & out , RSA_BLOCK_TYPE_2 ,
3152+ WC_RSA_OAEP_PAD , WC_HASH_TYPE_SHA256 , WC_MGF1SHA256 , NULL , 0 , 0 ,
3153+ (int )maxLen * 8 , HEAP_HINT ), 0 );
3154+ ExpectPtrEq (out , block + maxLen );
3155+
3156+ XMEMSET (block , 0 , maxLen + 1 );
3157+ out = NULL ;
3158+ #if defined(WOLFSSL_SMALL_STACK ) && !defined(WOLFSSL_NO_MALLOC )
3159+ /* Scratch buffer is allocated per block, so any length is handled. */
3160+ ExpectIntEQ (wc_RsaUnPad_ex (block , maxLen + 1 , & out , RSA_BLOCK_TYPE_2 ,
3161+ WC_RSA_OAEP_PAD , WC_HASH_TYPE_SHA256 , WC_MGF1SHA256 , NULL , 0 , 0 ,
3162+ (int )(maxLen + 1 ) * 8 , HEAP_HINT ), 0 );
3163+ ExpectPtrEq (out , block + maxLen + 1 );
3164+ #else
3165+ /* Scratch buffer is on stack: one byte more is rejected before the
3166+ * block is touched. */
3167+ ExpectIntEQ (wc_RsaUnPad_ex (block , maxLen + 1 , & out , RSA_BLOCK_TYPE_2 ,
3168+ WC_RSA_OAEP_PAD , WC_HASH_TYPE_SHA256 , WC_MGF1SHA256 , NULL , 0 , 0 ,
3169+ (int )(maxLen + 1 ) * 8 , HEAP_HINT ), WC_NO_ERR_TRACE (BAD_FUNC_ARG ));
3170+ ExpectNull (out );
3171+ #endif
3172+ }
3173+ XFREE (block , HEAP_HINT , DYNAMIC_TYPE_TMP_BUFFER );
3174+ #else
3175+ return TEST_SKIPPED ;
3176+ #endif
3177+ return EXPECT_RESULT ();
3178+ }
0 commit comments