@@ -1073,6 +1073,112 @@ int wp_encrypt_key_pkcs8(WOLFPROV_CTX* provCtx, int cipher,
10731073#endif
10741074}
10751075
1076+ #if defined(HAVE_PKCS8 ) && !defined(NO_PWDBASED )
1077+ /* DER encoding of the PBKDF2 OID (1.2.840.113549.1.5.12). */
1078+ static const unsigned char wp_pbkdf2_oid [] = {
1079+ 42 , 134 , 72 , 134 , 247 , 13 , 1 , 5 , 12
1080+ };
1081+
1082+ /*
1083+ * Detect whether a DER blob is a PBES2-encrypted PKCS#8 key by looking for the
1084+ * PBKDF2 OID near the start of the encryptionAlgorithm field. Avoids prompting
1085+ * for a passphrase on data that is not an encrypted key.
1086+ */
1087+ static int wp_is_pbkdf2_encrypted (const unsigned char * data , word32 len )
1088+ {
1089+ int found = 0 ;
1090+ word32 i ;
1091+
1092+ for (i = 0 ; (i < 40 ) && (i + sizeof (wp_pbkdf2_oid ) < len ); i ++ ) {
1093+ if (XMEMCMP (data + i , wp_pbkdf2_oid , sizeof (wp_pbkdf2_oid )) == 0 ) {
1094+ found = 1 ;
1095+ break ;
1096+ }
1097+ }
1098+
1099+ return found ;
1100+ }
1101+ #endif
1102+
1103+ /**
1104+ * Decrypt a PBES2 EncryptedPrivateKeyInfo to plaintext PKCS#8 in place, getting
1105+ * the passphrase from the callback. Returns 0 without prompting when the data
1106+ * is not a PBES2-encrypted key.
1107+ *
1108+ * @param [in, out] data On in, encrypted key; on out, plaintext PKCS#8.
1109+ * @param [in, out] len On in, encrypted length; on out, plaintext length.
1110+ * @param [in] pwCb Password callback.
1111+ * @param [in] pwCbArg Argument to pass to the password callback.
1112+ * @return 1 on success.
1113+ * @return 0 on failure or when the data is not an encrypted PKCS#8 key.
1114+ */
1115+ int wp_decrypt_key_pkcs8 (unsigned char * data , word32 * len ,
1116+ OSSL_PASSPHRASE_CALLBACK * pwCb , void * pwCbArg )
1117+ {
1118+ #if defined(HAVE_PKCS8 ) && !defined(NO_PWDBASED )
1119+ int ok = 1 ;
1120+ int rc ;
1121+ #ifdef WOLFSSL_SMALL_STACK
1122+ char * password = NULL ;
1123+ #else
1124+ char password [WP_EPKI_PASSWORD_MAX ];
1125+ #endif
1126+ size_t passwordSz = WP_EPKI_PASSWORD_MAX ;
1127+
1128+ WOLFPROV_ENTER (WP_LOG_COMP_PROVIDER , "wp_decrypt_key_pkcs8" );
1129+
1130+ /* Only handle data that looks like a PBES2-encrypted PKCS#8 key. */
1131+ if ((data == NULL ) || (!wp_is_pbkdf2_encrypted (data , * len ))) {
1132+ ok = 0 ;
1133+ }
1134+ #ifdef WOLFSSL_SMALL_STACK
1135+ if (ok ) {
1136+ password = (char * )XMALLOC (WP_EPKI_PASSWORD_MAX , NULL ,
1137+ DYNAMIC_TYPE_TMP_BUFFER );
1138+ if (password == NULL ) {
1139+ ok = 0 ;
1140+ }
1141+ }
1142+ #endif
1143+ /* Get the password from the callback. */
1144+ if (ok && (!pwCb (password , passwordSz , & passwordSz , NULL , pwCbArg ))) {
1145+ ok = 0 ;
1146+ }
1147+ if (ok ) {
1148+ /* Decrypt the key in place. */
1149+ rc = wc_DecryptPKCS8Key (data , * len , password , (int )passwordSz );
1150+ if (rc <= 0 ) {
1151+ WOLFPROV_MSG_DEBUG_RETCODE (WP_LOG_LEVEL_DEBUG , "wc_DecryptPKCS8Key" ,
1152+ rc );
1153+ ok = 0 ;
1154+ }
1155+ else {
1156+ * len = (word32 )rc ;
1157+ }
1158+ }
1159+
1160+ /* Password is sensitive - force zeroization. */
1161+ #ifdef WOLFSSL_SMALL_STACK
1162+ if (password != NULL ) {
1163+ wc_ForceZero (password , WP_EPKI_PASSWORD_MAX );
1164+ XFREE (password , NULL , DYNAMIC_TYPE_TMP_BUFFER );
1165+ }
1166+ #else
1167+ wc_ForceZero (password , sizeof (password ));
1168+ #endif
1169+
1170+ WOLFPROV_LEAVE (WP_LOG_COMP_PROVIDER , __FILE__ ":" WOLFPROV_STRINGIZE (__LINE__ ),
1171+ ok );
1172+ return ok ;
1173+ #else
1174+ (void )data ;
1175+ (void )len ;
1176+ (void )pwCb ;
1177+ (void )pwCbArg ;
1178+ return 0 ;
1179+ #endif
1180+ }
1181+
10761182/**
10771183 * Read data out of the core BIO.
10781184 *
0 commit comments