From 28144decefe530d9c28e09c7dbd5e3c8e3152615 Mon Sep 17 00:00:00 2001
From: Paul Bakker <p.j.bakker@polarssl.org>
Date: Mon, 24 Jun 2013 19:28:55 +0200
Subject: [PATCH] PKCS#5 v2 PBES2 support and use in PKCS#8 encrypted
 certificates

The error code POLARSSL_ERR_X509_PASSWORD_MISMATCH is now properly
returned in case of an encryption failure in the padding. The
POLARSSL_ERR_X509_PASSWORD_REQUIRED error code is only returned for PEM
formatted private keys as for DER formatted ones it is impossible to
distinguish if a DER blob is PKCS#8 encrypted or not.
(cherry picked from commit 1fd4321ba2016dfaff2b48c11f731fc9ccbd7ccf)

Conflicts:
	include/polarssl/error.h
	scripts/generate_errors.pl
---
 include/polarssl/error.h                     |   4 +-
 include/polarssl/pkcs5.h                     |  45 ++++-
 include/polarssl/x509.h                      |   2 +
 library/error.c                              |  20 +-
 library/pkcs5.c                              | 197 +++++++++++++++++++
 library/x509parse.c                          |  27 +++
 scripts/generate_errors.pl                   |   4 +-
 tests/data_files/pkcs8_pbes2_pbkdf2_3des.der | Bin 0 -> 1298 bytes
 tests/data_files/pkcs8_pbes2_pbkdf2_3des.key |  30 +++
 tests/data_files/pkcs8_pbes2_pbkdf2_des.key  |  29 +++
 tests/suites/test_suite_x509parse.data       |  28 +++
 11 files changed, 376 insertions(+), 10 deletions(-)
 create mode 100644 tests/data_files/pkcs8_pbes2_pbkdf2_3des.der
 create mode 100644 tests/data_files/pkcs8_pbes2_pbkdf2_3des.key
 create mode 100644 tests/data_files/pkcs8_pbes2_pbkdf2_des.key

diff --git a/include/polarssl/error.h b/include/polarssl/error.h
index 4e5f69ed5..42d19a316 100644
--- a/include/polarssl/error.h
+++ b/include/polarssl/error.h
@@ -72,14 +72,14 @@
  * SHA4      1  0x007A-0x007A
  * PBKDF2    1  0x007C-0x007C
  * ECP       1  0x007E-0x007E
- * PKCS5     1  0x007C-0x007C
  *
  * High-level module nr (3 bits - 0x1...-0x8...)
  * Name     ID  Nr of Errors
  * PEM      1   9
  * PKCS#12  1   3 (Started from top)
- * X509     2   21
+ * X509     2   23
  * DHM      3   6
+ * PKCS5    3   4 (Started from top)
  * RSA      4   9
  * ECP      4   1 (Started from top)
  * MD       5   4
diff --git a/include/polarssl/pkcs5.h b/include/polarssl/pkcs5.h
index 5530b586e..b8c742e97 100644
--- a/include/polarssl/pkcs5.h
+++ b/include/polarssl/pkcs5.h
@@ -31,6 +31,7 @@
 
 #include <string.h>
 
+#include "asn1.h"
 #include "md.h"
 
 #ifdef _MSC_VER
@@ -40,12 +41,54 @@ typedef UINT32 uint32_t;
 #include <inttypes.h>
 #endif
 
-#define POLARSSL_ERR_PKCS5_BAD_INPUT_DATA                -0x007C  /**< Bad input parameters to function. */
+#define POLARSSL_ERR_PKCS5_BAD_INPUT_DATA                  -0x3f80  /**< Bad input parameters to function. */
+#define POLARSSL_ERR_PKCS5_INVALID_FORMAT                  -0x3f00  /**< Unexpected ASN.1 data. */
+#define POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE             -0x3e80  /**< Requested encryption or digest alg not available. */
+#define POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH               -0x3e00  /**< Given private key password does not allow for correct decryption. */
+
+#define PKCS5_DECRYPT      0
+#define PKCS5_ENCRYPT      1
+
+/*
+ * PKCS#5 OIDs
+ */
+#define OID_PKCS5               "\x2a\x86\x48\x86\xf7\x0d\x01\x05"
+#define OID_PKCS5_PBES2         OID_PKCS5 "\x0d"
+#define OID_PKCS5_PBKDF2        OID_PKCS5 "\x0c"
+
+/*
+ * Encryption Algorithm OIDs
+ */
+#define OID_DES_CBC             "\x2b\x0e\x03\x02\x07"
+#define OID_DES_EDE3_CBC        "\x2a\x86\x48\x86\xf7\x0d\x03\x07"
+
+/*
+ * Digest Algorithm OIDs
+ */
+#define OID_HMAC_SHA1           "\x2a\x86\x48\x86\xf7\x0d\x02\x07"
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/**
+ * \brief          PKCS#5 PBES2 function
+ *
+ * \param pbe_params the ASN.1 algorithm parameters
+ * \param mode       either PKCS5_DECRYPT or PKCS5_ENCRYPT
+ * \param pwd        password to use when generating key
+ * \param plen       length of password
+ * \param data       data to process
+ * \param datalen    length of data
+ * \param output     output buffer
+ *
+ * \returns        0 on success, or a PolarSSL error code if verification fails.
+ */
+int pkcs5_pbes2( asn1_buf *pbe_params, int mode,
+                 const unsigned char *pwd,  size_t pwdlen,
+                 const unsigned char *data, size_t datalen,
+                 unsigned char *output );
+
 /**
  * \brief          PKCS#5 PBKDF2 using HMAC
  *
diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h
index df382eaea..8baee1579 100644
--- a/include/polarssl/x509.h
+++ b/include/polarssl/x509.h
@@ -67,6 +67,8 @@
 #define POLARSSL_ERR_X509_INVALID_INPUT                    -0x2A00  /**< Input invalid. */
 #define POLARSSL_ERR_X509_MALLOC_FAILED                    -0x2A80  /**< Allocation of memory failed. */
 #define POLARSSL_ERR_X509_FILE_IO_ERROR                    -0x2B00  /**< Read/write of file failed. */
+#define POLARSSL_ERR_X509_PASSWORD_REQUIRED                -0x2B80  /**< Private key password can't be empty. */
+#define POLARSSL_ERR_X509_PASSWORD_MISMATCH                -0x2C00  /**< Given private key password does not allow for correct decryption. */
 /* \} name */
 
 /**
diff --git a/library/error.c b/library/error.c
index 23f11f2c1..ae3234960 100644
--- a/library/error.c
+++ b/library/error.c
@@ -250,6 +250,17 @@ void error_strerror( int ret, char *buf, size_t buflen )
             snprintf( buf, buflen, "PKCS12 - PBE ASN.1 data not as expected" );
 #endif /* POLARSSL_PKCS12_C */
 
+#if defined(POLARSSL_PKCS5_C)
+        if( use_ret == -(POLARSSL_ERR_PKCS5_BAD_INPUT_DATA) )
+            snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" );
+        if( use_ret == -(POLARSSL_ERR_PKCS5_INVALID_FORMAT) )
+            snprintf( buf, buflen, "PKCS5 - Unexpected ASN.1 data" );
+        if( use_ret == -(POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE) )
+            snprintf( buf, buflen, "PKCS5 - Requested encryption or digest alg not available" );
+        if( use_ret == -(POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH) )
+            snprintf( buf, buflen, "PKCS5 - Given private key password does not allow for correct decryption" );
+#endif /* POLARSSL_PKCS5_C */
+
 #if defined(POLARSSL_RSA_C)
         if( use_ret == -(POLARSSL_ERR_RSA_BAD_INPUT_DATA) )
             snprintf( buf, buflen, "RSA - Bad input parameters to function" );
@@ -390,6 +401,10 @@ void error_strerror( int ret, char *buf, size_t buflen )
             snprintf( buf, buflen, "X509 - Allocation of memory failed" );
         if( use_ret == -(POLARSSL_ERR_X509_FILE_IO_ERROR) )
             snprintf( buf, buflen, "X509 - Read/write of file failed" );
+        if( use_ret == -(POLARSSL_ERR_X509_PASSWORD_REQUIRED) )
+            snprintf( buf, buflen, "X509 - Private key password can't be empty" );
+        if( use_ret == -(POLARSSL_ERR_X509_PASSWORD_MISMATCH) )
+            snprintf( buf, buflen, "X509 - Given private key password does not allow for correct decryption" );
 #endif /* POLARSSL_X509_PARSE_C */
 
         if( strlen( buf ) == 0 )
@@ -570,11 +585,6 @@ void error_strerror( int ret, char *buf, size_t buflen )
         snprintf( buf, buflen, "PBKDF2 - Bad input parameters to function" );
 #endif /* POLARSSL_PBKDF2_C */
 
-#if defined(POLARSSL_PKCS5_C)
-    if( use_ret == -(POLARSSL_ERR_PKCS5_BAD_INPUT_DATA) )
-        snprintf( buf, buflen, "PKCS5 - Bad input parameters to function" );
-#endif /* POLARSSL_PKCS5_C */
-
 #if defined(POLARSSL_SHA1_C)
     if( use_ret == -(POLARSSL_ERR_SHA1_FILE_IO_ERROR) )
         snprintf( buf, buflen, "SHA1 - Read/write error in file" );
diff --git a/library/pkcs5.c b/library/pkcs5.c
index 9e12434a2..fa9111541 100644
--- a/library/pkcs5.c
+++ b/library/pkcs5.c
@@ -38,6 +38,203 @@
 #if defined(POLARSSL_PKCS5_C)
 
 #include "polarssl/pkcs5.h"
+#include "polarssl/asn1.h"
+#include "polarssl/cipher.h"
+
+static int pkcs5_parse_pbkdf2_params( unsigned char **p,
+                                      const unsigned char *end,
+                                      asn1_buf *salt, int *iterations,
+                                      int *keylen, md_type_t *md_type )
+{
+    int ret;
+    size_t len = 0;
+    asn1_buf prf_alg_oid;
+
+    /*
+     *  PBKDF2-params ::= SEQUENCE {
+     *    salt              OCTET STRING,
+     *    iterationCount    INTEGER,
+     *    keyLength         INTEGER OPTIONAL
+     *    prf               AlgorithmIdentifier DEFAULT algid-hmacWithSHA1
+     *  }
+     *
+     */
+    if( ( ret = asn1_get_tag( p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+    }
+
+    end = *p + len;
+
+    if( ( ret = asn1_get_tag( p, end, &salt->len, ASN1_OCTET_STRING ) ) != 0 )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+
+    salt->p = *p;
+    *p += salt->len;
+
+    if( ( ret = asn1_get_int( p, end, iterations ) ) != 0 )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+
+    if( *p == end )
+        return( 0 );
+
+    if( ( ret = asn1_get_int( p, end, keylen ) ) != 0 )
+    {
+        if( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+            return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+    }
+
+    if( *p == end )
+        return( 0 );
+
+    if( ( ret = asn1_get_tag( p, end, &prf_alg_oid.len, ASN1_OID ) ) != 0 )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+
+    if( !OID_CMP( OID_HMAC_SHA1, &prf_alg_oid ) )
+        return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+    *md_type = POLARSSL_MD_SHA1;
+
+    if( *p != end )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT +
+                POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    return( 0 );
+}
+
+int pkcs5_pbes2( asn1_buf *pbe_params, int mode,
+                 const unsigned char *pwd,  size_t pwdlen,
+                 const unsigned char *data, size_t datalen,
+                 unsigned char *output )
+{
+    int ret, iterations = 0, keylen = 0;
+    unsigned char *p, *end, *end2;
+    asn1_buf kdf_alg_oid, enc_scheme_oid, salt;
+    md_type_t md_type = POLARSSL_MD_SHA1;
+    unsigned char key[32], iv[32];
+    size_t len = 0, olen = 0;
+    const md_info_t *md_info;
+    const cipher_info_t *cipher_info;
+    md_context_t md_ctx;
+    cipher_context_t cipher_ctx;
+
+    p = pbe_params->p;
+    end = p + pbe_params->len;
+
+    /*
+     *  PBES2-params ::= SEQUENCE {
+     *    keyDerivationFunc AlgorithmIdentifier {{PBES2-KDFs}},
+     *    encryptionScheme AlgorithmIdentifier {{PBES2-Encs}}
+     *  }
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+    }
+
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+    }
+
+    end2 = p + len;
+
+    if( ( ret = asn1_get_tag( &p, end2, &kdf_alg_oid.len, ASN1_OID ) ) != 0 )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+
+    kdf_alg_oid.p = p;
+    p += kdf_alg_oid.len;
+
+    // Only PBKDF2 supported at the moment
+    //
+    if( !OID_CMP( OID_PKCS5_PBKDF2, &kdf_alg_oid ) )
+        return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+    if( ( ret = pkcs5_parse_pbkdf2_params( &p, end2,
+                                           &salt, &iterations, &keylen,
+                                           &md_type ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    md_info = md_info_from_type( md_type );
+    if( md_info == NULL )
+        return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+    }
+
+    end2 = p + len;
+
+    if( ( ret = asn1_get_tag( &p, end2, &enc_scheme_oid.len, ASN1_OID ) ) != 0 )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+
+    enc_scheme_oid.p = p;
+    p += enc_scheme_oid.len;
+
+#if defined(POLARSSL_DES_C)
+    // Only DES-CBC and DES-EDE3-CBC supported at the moment
+    //
+    if( OID_CMP( OID_DES_EDE3_CBC, &enc_scheme_oid ) )
+    {
+        cipher_info = cipher_info_from_type( POLARSSL_CIPHER_DES_EDE3_CBC );
+    }
+    else if( OID_CMP( OID_DES_CBC, &enc_scheme_oid ) )
+    {
+        cipher_info = cipher_info_from_type( POLARSSL_CIPHER_DES_CBC );
+    }
+    else
+#endif /* POLARSSL_DES_C */
+        return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+    if( cipher_info == NULL )
+        return( POLARSSL_ERR_PKCS5_FEATURE_UNAVAILABLE );
+
+    keylen = cipher_info->key_length / 8;
+
+    if( ( ret = asn1_get_tag( &p, end2, &len, ASN1_OCTET_STRING ) ) != 0 )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT + ret );
+
+    if( len != cipher_info->iv_size )
+        return( POLARSSL_ERR_PKCS5_INVALID_FORMAT );
+
+    memcpy( iv, p, len );
+
+    if( ( ret = md_init_ctx( &md_ctx, md_info ) ) != 0 )
+        return( ret );
+
+    if( ( ret = cipher_init_ctx( &cipher_ctx, cipher_info ) ) != 0 )
+        return( ret );
+
+    if ( ( ret = pkcs5_pbkdf2_hmac( &md_ctx, pwd, pwdlen, salt.p, salt.len,
+                                    iterations, keylen, key ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    if( ( ret = cipher_setkey( &cipher_ctx, key, keylen, mode ) ) != 0 )
+        return( ret );
+
+    if( ( ret = cipher_reset( &cipher_ctx, iv ) ) != 0 )
+        return( ret );
+
+    if( ( ret = cipher_update( &cipher_ctx, data, datalen,
+                                output, &olen ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    if( ( ret = cipher_finish( &cipher_ctx, output + olen, &olen ) ) != 0 )
+        return( POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH );
+
+    return( 0 );
+}
 
 int pkcs5_pbkdf2_hmac( md_context_t *ctx, const unsigned char *password,
                        size_t plen, const unsigned char *salt, size_t slen,
diff --git a/library/x509parse.c b/library/x509parse.c
index bfc4b586a..f26b433e9 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -63,6 +63,9 @@
 #endif
 #include "polarssl/dhm.h"
 #include "polarssl/pkcs12.h"
+#if defined(POLARSSL_PKCS5_C)
+#include "polarssl/pkcs5.h"
+#endif
 
 #include <string.h>
 #include <stdlib.h>
@@ -2194,6 +2197,9 @@ static int x509parse_key_pkcs8_encrypted_der(
     p = (unsigned char *) key;
     end = p + keylen;
 
+    if( pwdlen == 0 )
+        return( POLARSSL_ERR_X509_PASSWORD_REQUIRED );
+
     /*
      * This function parses the EncryptedPrivatKeyInfo object (PKCS#8)
      *
@@ -2277,6 +2283,19 @@ static int x509parse_key_pkcs8_encrypted_der(
             return( ret );
         }
     }
+#if defined(POLARSSL_PKCS5_C)
+    else if( OID_CMP( OID_PKCS5_PBES2, &pbe_alg_oid ) )
+    {
+        if( ( ret = pkcs5_pbes2( &pbe_params, PKCS5_DECRYPT, pwd, pwdlen,
+                                  p, len, buf ) ) != 0 )
+        {
+            if( ret == POLARSSL_ERR_PKCS5_PASSWORD_MISMATCH )
+                return( POLARSSL_ERR_X509_PASSWORD_MISMATCH );
+
+            return( ret );
+        }
+    }
+#endif /* POLARSSL_PKCS5_C */
     else
         return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
 
@@ -2376,14 +2395,22 @@ int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen,
     }
 
     rsa_free( rsa );
+
+    if( ret == POLARSSL_ERR_X509_PASSWORD_MISMATCH )
+    {
+        return( ret );
+    }
+
     if( ( ret = x509parse_key_pkcs8_unencrypted_der( rsa, key, keylen ) ) == 0 )
         return( 0 );
 
     rsa_free( rsa );
+
     if( ( ret = x509parse_key_pkcs1_der( rsa, key, keylen ) ) == 0 )
         return( 0 );
 
     rsa_free( rsa );
+
     return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT );
 }
 
diff --git a/scripts/generate_errors.pl b/scripts/generate_errors.pl
index 5d8925e69..945ab6ad4 100755
--- a/scripts/generate_errors.pl
+++ b/scripts/generate_errors.pl
@@ -9,11 +9,11 @@ my $error_file = shift or die "Missing destination file";
 my $error_format_file = $data_dir.'/error.fmt';
 
 my @low_level_modules = ( "AES", "ASN1", "BLOWFISH", "CAMELLIA", "BIGNUM",
-                          "BASE64", "XTEA", "PBKDF2", "OID", "PKCS5",
+                          "BASE64", "XTEA", "PBKDF2", "OID",
                           "PADLOCK", "DES", "NET", "CTR_DRBG", "ENTROPY",
                           "MD2", "MD4", "MD5", "SHA1", "SHA2", "SHA4", "GCM" );
 my @high_level_modules = ( "PEM", "X509", "DHM", "RSA", "ECP", "MD", "CIPHER", "SSL",
-                           "PKCS12" );
+                           "PKCS12", "PKCS5" );
 
 my $line_separator = $/;
 undef $/;
diff --git a/tests/data_files/pkcs8_pbes2_pbkdf2_3des.der b/tests/data_files/pkcs8_pbes2_pbkdf2_3des.der
new file mode 100644
index 0000000000000000000000000000000000000000..75c573443b45403476840b15f8f4e54128963415
GIT binary patch
literal 1298
zcmV+t1?~DUf&~sRKn4jahDe6@4FLrWFf%Y41_>&LNQU<f0R;>&4g?7QqA4Emnk#<-
z0tf&w6b1+?hDe6@4Fd-R2+vfK<9z#(w*-O&$eSfk@eG>q0KM;tdSZ>r;gc)Wm&R#o
zrG*kd$_eL4_CjE^q{M#`l>NnSl_@ORXe$&OK&>(qF43ac0^+o%1YuuYgS6a}Y63r3
zrHN(Tm3Zv1yug22NTT6+VFJv#+E)egQ4m3#Fo8By2I7^tNTHWI=8&G08KhIq*lnJ{
zxzB0wcEC_L473s^&Hr&wb&=Qtih2}D5ulIjnk;Jdg9B#=UYc`25r4g;m4i%O#r>PZ
zb_3!@J<glPk>?LZ8^vIoLPbkoEV#OIk}&K+F6)PufaOIn!NxjD2@L=f&M{(k)i>-j
zVzeQh?h|=(FU((_qyUdV;I&d<c<JH(Z5yuu40*pY%?M#avC?FB!w_XKk-_L*X@6e;
zfzP-`a@uwVr$k=24WH7pf!Y57lU5D`-LZcG{^FYHNO1ZFrq%X5zpwLq`sxu^1_OHl
z%|0|@3n0YY{xo9olII_kE7+cmcz>7?9WXn|w7v;U)Yb{$IVa@Cm{2oJtFW(-KC?pC
zg+mQLdej;ziDV#&U>k{*&EiE7jw=xwinLw?wwAJ}V?=AsBJ)QzlIT>au>*Ew^U1>1
zvo`GC*F)M+kxAzbiuR5g!FFpMU2%wdRdBw+4WzMpi41k5Tcrd0fI{sP$kv4VI3;E4
z?-I4&+89RTbfQ%0RgCNG7<cl^-R!vETdyBlM+oJSaIEWz_x?06;Pv<_s{8XEOhTTb
zy;URVxQ@-hOJbfxx4!r1Wp+@Ru~`8NK`$d=Fc*fSmvF<5{bMVE^1uy0tWPdqq!%5+
zw0p6(sRC2|gs}b`0^d1A%joxc(4}aa`v1_;W(hu3los|bx8*vzKqJIZsou4kQTGYm
zRq+*RTv?`{{toOnQkrodYx$0UC5pLF#*J%+9m74W?iA#Fo_D6e0U$@s))qT`1~MH4
zSA`g7v{LdQh*OqRw7Nq{ojSwCE8Q*ueNFS_Au%!DDD|{mv!cZsWwB0IkJO2$gx)eV
z>pbpe#1tF7nzH%%v^(>5w$|d5`9vH<$bEp>nOYGttTjB*sV!rbcZLeBX6oh@;HZ%P
zmVK;6Bg3>Ma@JE}zJbi0mkPNI-G?z2zMh-Lx)AbH(nb37x~-;ZGM5C;>ZIfMqTTRd
zF$2%HFIMMJCm67@d{k-O_a$+7=HH4C{<f{;CS9BIVN3!`y=41$&trpyt;v(dkeeB%
z{h~Z%GsZfkBF{U214ZvpMlN_Spsk?S@ngIhu7X|iO0QcO*OtzJAI90K*e|vC<Z8pR
zF>TW7d6}04=OD68u!6QP_NRslQW#|FqUINMl%p$_IFCf^+`1+3WgUvSKM>~gFBYJF
zu<8~4#67vv$VQWBSlMohWp%fWY$z-iClY$>wPGjOL+iw=G6}*U3Uyb0*49zl4pd|W
z_<t&Sib>|@xJR9u5c|#L8L&w}$8{+7@TM`H%(@K&h%}k(*cO|{&OE+;9lqhJ0pN9p
zB7Yb8m-^3SUOwZ*wLr+8_{!hpB_|dBAR|;~a=u|Bl=T?n<k+>ptC`}eaL;jZ?*NkC
zi@?%|Qc;7r?j4&YBN|?(rWE+&NDa9}8mf#n$A<qywX*R@)yU~UOI5hSw28aUx^)Il
II}z{jyGVVA1ONa4

literal 0
HcmV?d00001

diff --git a/tests/data_files/pkcs8_pbes2_pbkdf2_3des.key b/tests/data_files/pkcs8_pbes2_pbkdf2_3des.key
new file mode 100644
index 000000000..a303daac3
--- /dev/null
+++ b/tests/data_files/pkcs8_pbes2_pbkdf2_3des.key
@@ -0,0 +1,30 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI4W7G1sVqHJMCAggA
+MBQGCCqGSIb3DQMHBAjXOQ/kHb9EVASCBMg68SwrdD/DLeKcPtCkE36wHvrK6wi7
+CjwFv2U/gIfNCUNXBZPI4G7voL1XOLJ8h0WWqlEraHo7zYWI5Ky98SI6wOpDGDzo
+URvavOVT3Ry/QfLtt0GZvELmJb6qO2AcL1qIDULx4xXqb3rI29xR/xVaCkB8CGSe
+JxU+1TbJJG0UdVDm28dhO8J4qgBpj9N6M/e8K1TIu8ty6IkFPFumTN9zMV9VXRIo
+Ajr1RDIiFXCZ4ayEnja2RIZwi89rn/iC/QzfsqQFr5axw58wz+0/EfD/i79gKoOX
+jKBEwWN44LsxJW/ucy3pm7xRurwZvOQZIeZcecVVecAaHmCRFfq+VpSnU5iDZEDL
+0GU+CKXW+zDnuIfUc/lx7LWjFyqR12OviS2CdrkaTKSVBAEYCFQdGPCp51WoZMnE
+uaKkLp0y58e5J0mHx4kmk2saAacdO/YolHjkh5zNe1Z+sORwPEo4ruZY/+wem/TG
+KFQsVjH/jAsyQFsyXaOrQ4QyOwxw52Vz6b7vrffaTdnKlyvJTvebEbhNiNmt2Ni+
+wac/1VcedkMpUrNmpJyal6lzWrVQmW1Q9qBinxHeGnNHk2QWTGZCQCClxDTfPoE1
+HC85cD4h91eBV4fiQm/ML/WmaGAQGUiTlX5vESJG1pKYXGqv1cr1pj+MTjqfjApl
+KOj93yAvx4ss42onWe9DPOBojSMuIzEVZOeq7mt7QeNpN9unjsDVrvq/fmsvIBb0
+t5HFVX4JlZoF2sfrwP0jEkyHxlk0pZZc5rbwtVI601MolDzjTNBcYbUB0IUlIj9f
+mM35IAFWZtrXXv3k5ZRFQU2jB7DFP9zHWsai7quhhduvt498rNxiWu7YlAQfhaU/
+wVK+3Fca7AGrlQ8YmzV0uOwoTMvKbLNwiiIG6QsgWRhmOIwHdNlRvhaZl6ybRLty
+ppMaqlOgDu88/8SMCce8yBderXW/0QxCZjQ3gEDufqxjC2IelOfEbChMLIs6p+9B
+qaPtji3TxOscQZMD9g4jYXUawHSq55B/MegD5sfvTl3ql+qsQnleXDUz2gJ+MBlH
+Qp6HZMs2woAbvFyxAXSUeKAOZrnW1TmRNmj6SwtE9aPmMwSYxZtTukesl+CpzEqi
+BdBZia3Yxu9Z5694Cg1eXoPIir6u6svZA5OIpEIUDIUPnMmG9pjxQ1xK40vyjdMZ
++9uAVdGX118nuwZ6Al4bfrPOOmwII2X1xmfFGG3rbVHVD9dIGJ1HGWPZio4F/eai
+kfSYHr0410JRAOvd9G4vrH6rq/zE5QcLCmXyH5W9vF3RJDAK4ArcaLF5RPY8slEJ
+NcZ7XTcKUc/Tg6VCMo3agozuzrxKCX5x6rvn0COYgdU3ozTO72dJlFQY2KpJP0n2
+RWWjdl2r7XYVRoQJd5XaZ3/mgJ7FtL42Rh6+vjEJLezWgUTo3B4Z0WG8WIp4wfAw
+d4qbAa4lVWtP++HZvIqOPaL+nZgFS22ygtoIVyYDj7lcqH9cdMsaMrZFAxisVQK2
+z2DnysfLg4dkdDuJjFUI07QUPwqjfRVKC8Mec45j9zrpuzu82zQ8Fub7ldtECsby
+oq0smBG1vd+ozMPnr3yvU7X7jaaM4toW+dG3OQxnUO2GyB/BAEamOB4CWWbKSfy1
+tfM=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/data_files/pkcs8_pbes2_pbkdf2_des.key b/tests/data_files/pkcs8_pbes2_pbkdf2_des.key
new file mode 100644
index 000000000..f3a2d0c60
--- /dev/null
+++ b/tests/data_files/pkcs8_pbes2_pbkdf2_des.key
@@ -0,0 +1,29 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIIFCzA9BgkqhkiG9w0BBQ0wMDAbBgkqhkiG9w0BBQwwDgQIE+lx5z79hVACAggA
+MBEGBSsOAwIHBAjrWP2/SiR7cwSCBMgUgnI4/ZG3jidt8TZShsbKzxQ9bt9D1URm
+8FBTFMk8JRowaXZyM2fx1/vEUlvKHIwpytOYO42py0lDf2qdn8iIe+8V2GLpyGcL
+ifWGbDt/ctEo2jVgWT01q2PfUEirwTPTUaDR5KBjfMjGM5V5c58fnTQztAFaXFmI
+VNkiQCC6AKCbmlblEcjFGBlRGgV8sOWCW+JaR5iJNdT6PhVJzJiQrfR819fGSISj
+0N0Wqpj3VA8V9BeATZAjvofBCwRABDNsDqRhjgx7ZEVz8C6pNK7Ck6ZXEjXaWc12
+ZvkzjLuufZ5B7klvgLzfxEtvZbQJmrQddDXZP9ICykP6D8W87EqEgk8yoxeFioOm
+0/edj7AVZ3rxbxpUUHJUiYDLNXaZTksfYhL0ZsB3cEL8VofUa1K+66N/0TismNDR
+4KSIjuRausXf1WJ1oh5B18zvnl2jkzCpwISf58d7UeOny3/ZR38B71EuaXO4r21e
+BrG6fi9VewuUg1DHSYLIJErVcfNnVXHuT0EzPTjr0vdTUguzDUv4/YFcpEDk5jnQ
+xJshBegjbt5W5gY3GTVRlyWqGKyOska3e2u4Cf7tZtP0kyy38JHLkQQXgj6dxseT
+lCIipBDJX3gU7yJHMiX/OpLcJuEMakRrpWLrB0vezX9oW0weE/dFzZeiYyo2K/DI
+TIFiL6FDuLUqpcYjeB1M+wbqs0f5ndXThVYi2/j73z0dwCI1WwKZH/WOdTrjYKxi
+0oiLz7pHHaPoMRymWCKTwQhYnqiOXZIpfeOFcUY4JKDzgyKdvU7XLPnbt4yxOlJD
+yAzX0i+bJjYjuG45XHTS8too0GFG2h6VFvOYAQsiq1qOnxVqVUvYphZBSz7D8Vql
+lHXWp954AhpfUQK4mLJq/exjUIGIZb/QxbNWNv7mTMkBQxGJ6B/1Vjkv9KC04KLe
+/JMnEZD+Sw5n+5j8qS6f7YOfVJ+Hqm04M1S8cc7JD4qMufLW/RvuKyBLb3sCn0Ue
+D+uiTedxoJR8nm6yI0uZ4d9RpRreca0PPt0o+DhbrDWyqH19kafN7I6SrDSbBNUO
+wiGBbgN4Ur9rPbzapATA/X95y+Q3CFLe/wcMLcLHJ3tnRCUo17Fx+APmrAsyBiYd
+9ulUq5WcZaw3pEDpTqN+0832UOyjIwpLyVDLU5jgW04vbW41o2SW7fCa7/QxT94p
+4PEAYi2MltPYQKRO7EOh+iUOHEsc8UDb6x4i75BcKhuLwZ7nmrwzg8ZO+TWMuzYb
+McJ11aZ42hN9U5H65FQzaZhAAcOqxTffQXIdARGlfvr3lTRnO/RQbxyObEqGeMHP
+XlDzvIMdB6b0RG4EBfpDFUpWf3Mhx4AG3bGHPjUXXhNICCMDdI49d0lNJ3nkF0nv
+JsehmIOY2U6fQBEnZhn5D0rjU+nUlHvgKQKhs9yIym/K+KVUznJW4ygwFiKXysVq
+QGqfn7hbBonYqLkGL99O9JyKgz/RhEMC0dKtgu6ELYJJVWnkJGTIMkp5a8ID48qW
+RmFJX+v5ryvM9ePSUbLizOUddsXycJpGsu+Am5H20cTPXkwxYtNcu49eLrGoXf7E
+/mD/zDqFryMK3oUBHnBJf0k/mMnzwfgHNveXApOSbflvRx39652Wugd7CxcOrIA=
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 19073e0b0..b039ea71e 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -130,6 +130,34 @@ X509 Parse Key #13 (PKCS#8 encrypted SHA1-RC4-128)
 depends_on:POLARSSL_ARC4_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO
 x509parse_keyfile:"data_files/pkcs8_pbe_sha1_rc4_128.key":"PolarSSLTest":0
 
+X509 Parse Key #14 (PKCS#8 encrypted v2 PBDFK2 3DES)
+depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO
+x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.key":"PolarSSLTest":0
+
+X509 Parse Key #15 (PKCS#8 encrypted v2 PBDFK2 3DES, wrong PW)
+depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO
+x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.key":"PolarSSLTes":POLARSSL_ERR_X509_PASSWORD_MISMATCH
+
+X509 Parse Key #16 (PKCS#8 encrypted v2 PBDFK2 3DES, no PW)
+depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO
+x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.key":"":POLARSSL_ERR_X509_PASSWORD_REQUIRED
+
+X509 Parse Key #17 (PKCS#8 encrypted v2 PBDFK2 3DES DER)
+depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_FS_IO
+x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.der":"PolarSSLTest":0
+
+X509 Parse Key #18 (PKCS#8 encrypted v2 PBDFK2 3DES DER, wrong PW)
+depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_FS_IO
+x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.der":"PolarSSLTes":POLARSSL_ERR_X509_PASSWORD_MISMATCH
+
+X509 Parse Key #19 (PKCS#8 encrypted v2 PBDFK2 3DES DER, no PW)
+depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_FS_IO
+x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.der":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
+
+X509 Parse Key #20 (PKCS#8 encrypted v2 PBDFK2 DES)
+depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO
+x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_des.key":"PolarSSLTest":0
+
 X509 Parse Public Key #1 (PKCS#8 wrapped)
 depends_on:POLARSSL_MD5_C:POLARSSL_PEM_C:POLARSSL_FS_IO
 x509parse_public_keyfile:"data_files/format_gen.pub":0