Merge branch 'parse-ec-key' into development
diff --git a/doxygen/input/doc_x509.h b/doxygen/input/doc_x509.h
index 56bb49b..16fe75a 100644
--- a/doxygen/input/doc_x509.h
+++ b/doxygen/input/doc_x509.h
@@ -11,8 +11,8 @@
  *   \c x509parse_crtfile()).
  * - X.509 certificate revocation list (CRL) reading (see \c x509parse_crl()
  *   and\c x509parse_crlfile()).
- * - X.509 (RSA) private key reading (see \c x509parse_key() and
- *   \c x509parse_keyfile()).
+ * - X.509 (RSA) private key reading (see \c x509parse_key_rsa() and
+ *   \c x509parse_keyfile_rsa()).
  * - X.509 certificate signature verification (see \c x509parse_verify())
  *
  * This module can be used to build a certificate authority (CA) chain and
diff --git a/include/polarssl/ecdsa.h b/include/polarssl/ecdsa.h
index 2ad986d..e709b40 100644
--- a/include/polarssl/ecdsa.h
+++ b/include/polarssl/ecdsa.h
@@ -29,6 +29,20 @@
 
 #include "polarssl/ecp.h"
 
+/**
+ * \brief           ECDSA context structure
+ */
+typedef struct
+{
+    ecp_group grp;      /*!<  ellipitic curve used          */
+    mpi d;              /*!<  secret signature key          */
+    ecp_point Q;        /*!<  public signature key          */
+    mpi r;              /*!<  first integer from signature  */
+    mpi s;              /*!<  second integer from signature */
+    int point_format;   /*!<  format for point export       */
+}
+ecdsa_context;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -71,6 +85,20 @@
                   const ecp_point *Q, const mpi *r, const mpi *s);
 
 /**
+ * \brief           Initialize context
+ *
+ * \param ctx       Context to initialize
+ */
+void ecdsa_init( ecdsa_context *ctx );
+
+/**
+ * \brief           Free context
+ *
+ * \param ctx       Context to free
+ */
+void ecdsa_free( ecdsa_context *ctx );
+
+/**
  * \brief          Checkup routine
  *
  * \return         0 if successful, or 1 if the test failed
diff --git a/include/polarssl/ecp.h b/include/polarssl/ecp.h
index 4b02181..c1f08c9 100644
--- a/include/polarssl/ecp.h
+++ b/include/polarssl/ecp.h
@@ -92,6 +92,25 @@
 ecp_group;
 
 /**
+ * \brief           ECP key pair structure
+ *
+ * A generic key pair that could be used for ECDSA, fixed ECDH, etc.
+ * Usage can be restricted to a particular algorithm by the 'alg' field,
+ * see POLARSSL_ECP_KEY_ALG_* constants (default: unrestricted).
+ *
+ * \sa ecdh_context
+ * \sa ecdsa_context
+ */
+typedef struct
+{
+    ecp_group grp;      /*!<  Elliptic curve and base point     */
+    mpi d;              /*!<  our secret value                  */
+    ecp_point Q;        /*!<  our public value                  */
+    int alg;            /*!<  algorithm to use this key with    */
+}
+ecp_keypair;
+
+/**
  * RFC 5114 defines a number of standardized ECP groups for use with TLS.
  *
  * These also are the NIST-recommended ECP groups, are the random ECP groups
@@ -139,6 +158,16 @@
  */
 #define POLARSSL_ECP_TLS_NAMED_CURVE    3   /**< ECCurveType's named_curve */
 
+/*
+ * Algorithm identifiers from RFC 5480 for use with EC keys
+ */
+#define POLARSSL_ECP_KEY_ALG_UNRESTRICTED   0   /**< RFC 5480 2.1.1 */
+#define POLARSSL_ECP_KEY_ALG_ECDH           1   /**< RFC 5480 2.1.2 */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 /**
  * \brief           Initialize a point (as zero)
  */
@@ -150,6 +179,11 @@
 void ecp_group_init( ecp_group *grp );
 
 /**
+ * \brief           Initialize a key pair (as an invalid one)
+ */
+void ecp_keypair_init( ecp_keypair *key );
+
+/**
  * \brief           Free the components of a point
  */
 void ecp_point_free( ecp_point *pt );
@@ -160,6 +194,11 @@
 void ecp_group_free( ecp_group *grp );
 
 /**
+ * \brief           Free the components of a key pair
+ */
+void ecp_keypair_free( ecp_keypair *key );
+
+/**
  * \brief           Set a point to zero
  *
  * \param pt        Destination point
@@ -190,25 +229,6 @@
 int ecp_copy( ecp_point *P, const ecp_point *Q );
 
 /**
- * \brief           Check that a point is a valid public key on this curve
- *
- * \param grp       Curve/group the point should belong to
- * \param pt        Point to check
- *
- * \return          0 if point is a valid public key,
- *                  POLARSSL_ERR_ECP_GENERIC otherwise.
- *
- * \note            This function only checks the point is non-zero, has valid
- *                  coordinates and lies on the curve, but not that it is
- *                  indeed a multiple of G. This is additional check is more
- *                  expensive, isn't required by standards, and shouldn't be
- *                  necessary if the group used has a small cofactor. In
- *                  particular, it is useless for the NIST groups which all
- *                  have a cofactor of 1.
- */
-int ecp_check_pubkey( const ecp_group *grp, const ecp_point *pt );
-
-/**
  * \brief           Import a non-zero point from two ASCII strings
  *
  * \param P         Destination point
@@ -399,6 +419,44 @@
              const mpi *m, const ecp_point *P );
 
 /**
+ * \brief           Check that a point is a valid public key on this curve
+ *
+ * \param grp       Curve/group the point should belong to
+ * \param pt        Point to check
+ *
+ * \return          0 if point is a valid public key,
+ *                  POLARSSL_ERR_ECP_GENERIC otherwise.
+ *
+ * \note            This function only checks the point is non-zero, has valid
+ *                  coordinates and lies on the curve, but not that it is
+ *                  indeed a multiple of G. This is additional check is more
+ *                  expensive, isn't required by standards, and shouldn't be
+ *                  necessary if the group used has a small cofactor. In
+ *                  particular, it is useless for the NIST groups which all
+ *                  have a cofactor of 1.
+ *
+ * \note            Uses bare components rather than an ecp_keypair structure
+ *                  in order to ease use with other structures such as
+ *                  ecdh_context of ecdsa_context.
+ */
+int ecp_check_pubkey( const ecp_group *grp, const ecp_point *pt );
+
+/**
+ * \brief           Check that an mpi is a valid private key for this curve
+ *
+ * \param grp       Group used
+ * \param d         Integer to check
+ *
+ * \return          0 if point is a valid private key,
+ *                  POLARSSL_ERR_ECP_GENERIC otherwise.
+ *
+ * \note            Uses bare components rather than an ecp_keypair structure
+ *                  in order to ease use with other structures such as
+ *                  ecdh_context of ecdsa_context.
+ */
+int ecp_check_privkey( const ecp_group *grp, const mpi *d );
+
+/**
  * \brief           Generate a keypair
  *
  * \param grp       ECP group
@@ -409,6 +467,10 @@
  *
  * \return          0 if successful,
  *                  or a POLARSSL_ERR_ECP_XXX or POLARSSL_MPI_XXX error code
+ *
+ * \note            Uses bare components rather than an ecp_keypair structure
+ *                  in order to ease use with other structures such as
+ *                  ecdh_context of ecdsa_context.
  */
 int ecp_gen_keypair( const ecp_group *grp, mpi *d, ecp_point *Q,
                      int (*f_rng)(void *, unsigned char *, size_t),
diff --git a/include/polarssl/error.h b/include/polarssl/error.h
index c326154..f8c23e6 100644
--- a/include/polarssl/error.h
+++ b/include/polarssl/error.h
@@ -76,7 +76,8 @@
  * Name     ID  Nr of Errors
  * PEM      1   9
  * PKCS#12  1   4 (Started from top)
- * X509     2   23
+ * X509     2   25
+ * PK       2   1 (Started from top)
  * DHM      3   6
  * PKCS5    3   4 (Started from top)
  * RSA      4   9
diff --git a/include/polarssl/oid.h b/include/polarssl/oid.h
index e63c169..a39055b 100644
--- a/include/polarssl/oid.h
+++ b/include/polarssl/oid.h
@@ -31,7 +31,6 @@
 #include "config.h"
 #include "asn1.h"
 #include "pk.h"
-
 #if defined(POLARSSL_CIPHER_C)
 #include "cipher.h"
 #endif
@@ -61,6 +60,9 @@
 #define OID_ORG_RSA_DATA_SECURITY       "\x86\xf7\x0d"  /* {rsadsi(113549)} */
 #define OID_RSA_COMPANY                 OID_ISO_MEMBER_BODIES OID_COUNTRY_US    \
                                         OID_ORG_RSA_DATA_SECURITY /* {iso(1) member-body(2) us(840) rsadsi(113549)} */
+#define OID_ORG_ANSI_X9_62              "\xce\x3d" /* ansi-X9-62(10045) */
+#define OID_ANSI_X9_62                  OID_ISO_MEMBER_BODIES OID_COUNTRY_US \
+                                        OID_ORG_ANSI_X9_62
 
 /*
  * ISO Identified organization OID parts
@@ -70,6 +72,8 @@
 #define OID_OIW_SECSIG                  OID_ORG_OIW "\x03"
 #define OID_OIW_SECSIG_ALG              OID_OIW_SECSIG "\x02"
 #define OID_OIW_SECSIG_SHA1             OID_OIW_SECSIG_ALG "\x1a"
+#define OID_ORG_CERTICOM                "\x81\x04"  /* certicom(132) */
+#define OID_CERTICOM                    OID_ISO_IDENTIFIED_ORG OID_ORG_CERTICOM
 
 /*
  * ISO ITU OID parts
@@ -235,6 +239,43 @@
 #define OID_PKCS12_PBE_SHA1_RC2_128_CBC     OID_PKCS12_PBE "\x05" /**< pbeWithSHAAnd128BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 5} */
 #define OID_PKCS12_PBE_SHA1_RC2_40_CBC      OID_PKCS12_PBE "\x06" /**< pbeWithSHAAnd40BitRC2-CBC OBJECT IDENTIFIER ::= {pkcs-12PbeIds 6} */
 
+/*
+ * EC key algorithms from RFC 5480
+ */
+
+/* id-ecPublicKey OBJECT IDENTIFIER ::= {
+ *       iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } */
+#define OID_EC_ALG_UNRESTRICTED         OID_ANSI_X9_62 "\x02\01"
+
+/*   id-ecDH OBJECT IDENTIFIER ::= {
+ *     iso(1) identified-organization(3) certicom(132)
+ *     schemes(1) ecdh(12) } */
+#define OID_EC_ALG_ECDH                 OID_CERTICOM "\x01\x0c"
+
+/*
+ * ECParameters namedCurve identifiers, from RFC 5480
+ */
+
+/* secp192r1 OBJECT IDENTIFIER ::= {
+ *   iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 1 } */
+#define OID_EC_GRP_SECP192R1        OID_ANSI_X9_62 "\x03\x01\x01"
+
+/* secp224r1 OBJECT IDENTIFIER ::= {
+ *   iso(1) identified-organization(3) certicom(132) curve(0) 33 } */
+#define OID_EC_GRP_SECP224R1        OID_CERTICOM "\x00\x21"
+
+/* secp256r1 OBJECT IDENTIFIER ::= {
+ *   iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) prime(1) 7 } */
+#define OID_EC_GRP_SECP256R1        OID_ANSI_X9_62 "\x03\x01\x07"
+
+/* secp384r1 OBJECT IDENTIFIER ::= {
+ *   iso(1) identified-organization(3) certicom(132) curve(0) 34 } */
+#define OID_EC_GRP_SECP384R1        OID_CERTICOM "\x00\x22"
+
+/* secp521r1 OBJECT IDENTIFIER ::= {
+ *   iso(1) identified-organization(3) certicom(132) curve(0) 35 } */
+#define OID_EC_GRP_SECP521R1        OID_CERTICOM "\x00\x23"
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -293,6 +334,16 @@
  */
 int oid_get_pk_alg( const asn1_buf *oid, pk_type_t *pk_alg );
 
+/**
+ * \brief          Translate ECParameters OID into an EC group identifier
+ *
+ * \param oid      OID to use
+ * \param grp_id   place to store group id
+ *
+ * \return         0 if successful, or POLARSSL_ERR_OID_NOT_FOUND
+ */
+int oid_get_ec_grp( const asn1_buf *oid, ecp_group_id *grp_id );
+
 #if defined(POLARSSL_MD_C)
 /**
  * \brief          Translate SignatureAlgorithm OID into md_type and pk_type
diff --git a/include/polarssl/pem.h b/include/polarssl/pem.h
index 969faa2..cc6cba1 100644
--- a/include/polarssl/pem.h
+++ b/include/polarssl/pem.h
@@ -84,6 +84,10 @@
  *                  POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT, use_len is
  *                  the length to skip)
  *
+ * \note            Attempts to check password correctness by verifying if
+ *                  the decrypted text starts with an ASN.1 sequence of
+ *                  appropriate length
+ *
  * \return          0 on success, ior a specific PEM error code
  */
 int pem_read_buffer( pem_context *ctx, const char *header, const char *footer,
diff --git a/include/polarssl/pk.h b/include/polarssl/pk.h
index d9639ee..00f8cfc 100644
--- a/include/polarssl/pk.h
+++ b/include/polarssl/pk.h
@@ -27,6 +27,8 @@
 #ifndef POLARSSL_PK_H
 #define POLARSSL_PK_H
 
+#define POLARSSL_ERR_PK_MALLOC_FAILED       -0x2F80  /**< Memory alloation failed. */
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -36,10 +38,44 @@
  */
 typedef enum {
     POLARSSL_PK_NONE=0,
+#if defined(POLARSSL_RSA_C)
     POLARSSL_PK_RSA,
-    POLARSSL_PK_ECDSA,
+#endif
+#if defined(POLARSSL_ECP_C)
+    POLARSSL_PK_ECKEY,
+    POLARSSL_PK_ECKEY_DH,
+#endif
 } pk_type_t;
 
+/**
+ * \brief           Public key container
+ */
+typedef struct
+{
+    pk_type_t   type;   /**< Public key type */
+    void *      data;   /**< Public key data */
+} pk_context;
+
+/**
+ * \brief           Initialize a pk_context (as NONE)
+ */
+void pk_init( pk_context *ctx );
+
+/**
+ * \brief           Free a pk_context
+ */
+void pk_free( pk_context *ctx );
+
+/**
+ * \brief           Set a pk_context to a given type
+ *
+ * \param ctx       Context to initialize
+ * \param type      Type of key
+ *
+ * \return          O on success, or POLARSSL_ERR_PK_MALLOC_FAILED
+ */
+int pk_set_type( pk_context *ctx, pk_type_t type );
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/include/polarssl/x509.h b/include/polarssl/x509.h
index 86624ec..f0c0e7a 100644
--- a/include/polarssl/x509.h
+++ b/include/polarssl/x509.h
@@ -32,6 +32,7 @@
 #if defined(POLARSSL_X509_PARSE_C) || defined(POLARSSL_X509_WRITE_C)
 #include "asn1.h"
 #include "rsa.h"
+#include "ecp.h"
 #include "dhm.h"
 #include "md.h"
 #include "pk.h"
@@ -58,7 +59,7 @@
 #define POLARSSL_ERR_X509_CERT_INVALID_EXTENSIONS          -0x2580  /**< The extension tag or value is invalid. */
 #define POLARSSL_ERR_X509_CERT_UNKNOWN_VERSION             -0x2600  /**< Certificate or CRL has an unsupported version number. */
 #define POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG             -0x2680  /**< Signature algorithm (oid) is unsupported. */
-#define POLARSSL_ERR_X509_UNKNOWN_PK_ALG                   -0x2700  /**< Key algorithm is unsupported (only RSA is supported). */
+#define POLARSSL_ERR_X509_UNKNOWN_PK_ALG                   -0x2700  /**< Key algorithm is unsupported (only RSA and EC are supported). */
 #define POLARSSL_ERR_X509_CERT_SIG_MISMATCH                -0x2780  /**< Certificate signature algorithms do not match. (see \c ::x509_cert sig_oid) */
 #define POLARSSL_ERR_X509_CERT_VERIFY_FAILED               -0x2800  /**< Certificate verification failed, e.g. CRL, CA or signature check failed. */
 #define POLARSSL_ERR_X509_KEY_INVALID_VERSION              -0x2880  /**< Unsupported RSA key version */
@@ -69,6 +70,7 @@
 #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. */
+#define POLARSSL_ERR_X509_UNKNOWN_NAMED_CURVE              -0x2C80  /**< Elliptic curve is unsupported (only NIST curves are supported). */
 /* \} name */
 
 /**
@@ -427,9 +429,9 @@
  *
  * \return         0 if successful, or a specific X509 or PEM error code
  */
-int x509parse_key( rsa_context *rsa,
-                   const unsigned char *key, size_t keylen,
-                   const unsigned char *pwd, size_t pwdlen );
+int x509parse_key_rsa( rsa_context *rsa,
+                       const unsigned char *key, size_t keylen,
+                       const unsigned char *pwd, size_t pwdlen );
 
 /** \ingroup x509_module */
 /**
@@ -441,8 +443,8 @@
  *
  * \return         0 if successful, or a specific X509 or PEM error code
  */
-int x509parse_keyfile( rsa_context *rsa, const char *path,
-                       const char *password );
+int x509parse_keyfile_rsa( rsa_context *rsa, const char *path,
+                           const char *password );
 
 /** \ingroup x509_module */
 /**
@@ -454,8 +456,8 @@
  *
  * \return         0 if successful, or a specific X509 or PEM error code
  */
-int x509parse_public_key( rsa_context *rsa,
-                   const unsigned char *key, size_t keylen );
+int x509parse_public_key_rsa( rsa_context *rsa,
+                       const unsigned char *key, size_t keylen );
 
 /** \ingroup x509_module */
 /**
@@ -466,7 +468,60 @@
  *
  * \return         0 if successful, or a specific X509 or PEM error code
  */
-int x509parse_public_keyfile( rsa_context *rsa, const char *path );
+int x509parse_public_keyfile_rsa( rsa_context *rsa, const char *path );
+
+/** \ingroup x509_module */
+/**
+ * \brief          Parse a private key
+ *
+ * \param ctx      key to be initialized
+ * \param key      input buffer
+ * \param keylen   size of the buffer
+ * \param pwd      password for decryption (optional)
+ * \param pwdlen   size of the password
+ *
+ * \return         0 if successful, or a specific X509 or PEM error code
+ */
+int x509parse_key( pk_context *ctx,
+                   const unsigned char *key, size_t keylen,
+                   const unsigned char *pwd, size_t pwdlen );
+
+/** \ingroup x509_module */
+/**
+ * \brief          Load and parse a private key
+ *
+ * \param ctx      key to be initialized
+ * \param path     filename to read the private key from
+ * \param password password to decrypt the file (can be NULL)
+ *
+ * \return         0 if successful, or a specific X509 or PEM error code
+ */
+int x509parse_keyfile( pk_context *ctx,
+                       const char *path, const char *password );
+
+/** \ingroup x509_module */
+/**
+ * \brief          Parse a public key
+ *
+ * \param ctx      key to be initialized
+ * \param key      input buffer
+ * \param keylen   size of the buffer
+ *
+ * \return         0 if successful, or a specific X509 or PEM error code
+ */
+int x509parse_public_key( pk_context *ctx,
+                          const unsigned char *key, size_t keylen );
+
+/** \ingroup x509_module */
+/**
+ * \brief          Load and parse a public key
+ *
+ * \param ctx      key to be initialized
+ * \param path     filename to read the private key from
+ *
+ * \return         0 if successful, or a specific X509 or PEM error code
+ */
+int x509parse_public_keyfile( pk_context *ctx, const char *path );
 
 /** \ingroup x509_module */
 /**
diff --git a/library/CMakeLists.txt b/library/CMakeLists.txt
index 948737d..3fa76a9 100644
--- a/library/CMakeLists.txt
+++ b/library/CMakeLists.txt
@@ -39,6 +39,7 @@
      pkcs5.c
      pkcs11.c
      pkcs12.c
+     pk.c
      rsa.c
      sha1.c
      sha256.c
diff --git a/library/Makefile b/library/Makefile
index f670dcc..48c3bdc 100644
--- a/library/Makefile
+++ b/library/Makefile
@@ -49,6 +49,7 @@
 		oid.o									\
 		padlock.o	pbkdf2.o	pem.o			\
 		pkcs5.o		pkcs11.o	pkcs12.o		\
+		pk.o									\
 		rsa.o		sha1.o		sha256.o		\
 		sha512.o	ssl_cache.o	ssl_cli.o		\
 		ssl_srv.o   ssl_ciphersuites.o			\
diff --git a/library/ecdsa.c b/library/ecdsa.c
index d683457..11b7f5e 100644
--- a/library/ecdsa.c
+++ b/library/ecdsa.c
@@ -174,6 +174,33 @@
     return( ret );
 }
 
+/*
+ * Initialize context
+ */
+void ecdsa_init( ecdsa_context *ctx )
+{
+    ecp_group_init( &ctx->grp );
+    mpi_init( &ctx->d );
+    ecp_point_init( &ctx->Q );
+    mpi_init( &ctx->r );
+    mpi_init( &ctx->s );
+    mpi_init( &ctx->d );
+    ctx->point_format = POLARSSL_ECP_PF_UNCOMPRESSED;
+}
+
+/*
+ * Free context
+ */
+void ecdsa_free( ecdsa_context *ctx )
+{
+    ecp_group_free( &ctx->grp );
+    mpi_free( &ctx->d );
+    ecp_point_free( &ctx->Q );
+    mpi_free( &ctx->r );
+    mpi_free( &ctx->s );
+    mpi_free( &ctx->d );
+    ctx->point_format = POLARSSL_ECP_PF_UNCOMPRESSED;
+}
 
 #if defined(POLARSSL_SELF_TEST)
 
diff --git a/library/ecp.c b/library/ecp.c
index af18e5b..9e7a967 100644
--- a/library/ecp.c
+++ b/library/ecp.c
@@ -91,6 +91,20 @@
 }
 
 /*
+ * Initialize (the components of) a key pair
+ */
+void ecp_keypair_init( ecp_keypair *key )
+{
+    if ( key == NULL )
+        return;
+
+    ecp_group_init( &key->grp );
+    mpi_init( &key->d );
+    ecp_point_init( &key->Q );
+    key->alg = POLARSSL_ECP_KEY_ALG_UNRESTRICTED;
+}
+
+/*
  * Unallocate (the components of) a point
  */
 void ecp_point_free( ecp_point *pt )
@@ -118,6 +132,20 @@
 }
 
 /*
+ * Unallocate (the components of) a key pair
+ */
+void ecp_keypair_free( ecp_keypair *key )
+{
+    if ( key == NULL )
+        return;
+
+    ecp_group_free( &key->grp );
+    mpi_free( &key->d );
+    ecp_point_free( &key->Q );
+    key->alg = POLARSSL_ECP_KEY_ALG_UNRESTRICTED;
+}
+
+/*
  * Set point to zero
  */
 int ecp_set_zero( ecp_point *pt )
@@ -700,51 +728,6 @@
         MPI_CHK( mpi_sub_mpi( &N, &N, &grp->P ) )
 
 /*
- * Check that a point is valid as a public key (SEC1 3.2.3.1)
- */
-int ecp_check_pubkey( const ecp_group *grp, const ecp_point *pt )
-{
-    int ret;
-    mpi YY, RHS;
-
-    if( mpi_cmp_int( &pt->Z, 0 ) == 0 )
-        return( POLARSSL_ERR_ECP_GENERIC );
-
-    /*
-     * pt coordinates must be normalized for our checks
-     */
-    if( mpi_cmp_int( &pt->Z, 1 ) != 0 )
-        return( POLARSSL_ERR_ECP_GENERIC );
-
-    if( mpi_cmp_int( &pt->X, 0 ) < 0 ||
-        mpi_cmp_int( &pt->Y, 0 ) < 0 ||
-        mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 ||
-        mpi_cmp_mpi( &pt->Y, &grp->P ) >= 0 )
-        return( POLARSSL_ERR_ECP_GENERIC );
-
-    mpi_init( &YY ); mpi_init( &RHS );
-
-    /*
-     * YY = Y^2
-     * RHS = X (X^2 - 3) + B = X^3 - 3X + B
-     */
-    MPI_CHK( mpi_mul_mpi( &YY,  &pt->Y,  &pt->Y   ) );  MOD_MUL( YY  );
-    MPI_CHK( mpi_mul_mpi( &RHS, &pt->X,  &pt->X   ) );  MOD_MUL( RHS );
-    MPI_CHK( mpi_sub_int( &RHS, &RHS,    3        ) );  MOD_SUB( RHS );
-    MPI_CHK( mpi_mul_mpi( &RHS, &RHS,    &pt->X   ) );  MOD_MUL( RHS );
-    MPI_CHK( mpi_add_mpi( &RHS, &RHS,    &grp->B  ) );  MOD_ADD( RHS );
-
-    if( mpi_cmp_mpi( &YY, &RHS ) != 0 )
-        ret = POLARSSL_ERR_ECP_GENERIC;
-
-cleanup:
-
-    mpi_free( &YY ); mpi_free( &RHS );
-
-    return( ret );
-}
-
-/*
  * Normalize jacobian coordinates so that Z == 0 || Z == 1  (GECC 3.2.1)
  */
 static int ecp_normalize( const ecp_group *grp, ecp_point *pt )
@@ -1278,6 +1261,63 @@
 }
 
 /*
+ * Check that a point is valid as a public key (SEC1 3.2.3.1)
+ */
+int ecp_check_pubkey( const ecp_group *grp, const ecp_point *pt )
+{
+    int ret;
+    mpi YY, RHS;
+
+    if( mpi_cmp_int( &pt->Z, 0 ) == 0 )
+        return( POLARSSL_ERR_ECP_GENERIC );
+
+    /*
+     * pt coordinates must be normalized for our checks
+     */
+    if( mpi_cmp_int( &pt->Z, 1 ) != 0 )
+        return( POLARSSL_ERR_ECP_GENERIC );
+
+    if( mpi_cmp_int( &pt->X, 0 ) < 0 ||
+        mpi_cmp_int( &pt->Y, 0 ) < 0 ||
+        mpi_cmp_mpi( &pt->X, &grp->P ) >= 0 ||
+        mpi_cmp_mpi( &pt->Y, &grp->P ) >= 0 )
+        return( POLARSSL_ERR_ECP_GENERIC );
+
+    mpi_init( &YY ); mpi_init( &RHS );
+
+    /*
+     * YY = Y^2
+     * RHS = X (X^2 - 3) + B = X^3 - 3X + B
+     */
+    MPI_CHK( mpi_mul_mpi( &YY,  &pt->Y,  &pt->Y   ) );  MOD_MUL( YY  );
+    MPI_CHK( mpi_mul_mpi( &RHS, &pt->X,  &pt->X   ) );  MOD_MUL( RHS );
+    MPI_CHK( mpi_sub_int( &RHS, &RHS,    3        ) );  MOD_SUB( RHS );
+    MPI_CHK( mpi_mul_mpi( &RHS, &RHS,    &pt->X   ) );  MOD_MUL( RHS );
+    MPI_CHK( mpi_add_mpi( &RHS, &RHS,    &grp->B  ) );  MOD_ADD( RHS );
+
+    if( mpi_cmp_mpi( &YY, &RHS ) != 0 )
+        ret = POLARSSL_ERR_ECP_GENERIC;
+
+cleanup:
+
+    mpi_free( &YY ); mpi_free( &RHS );
+
+    return( ret );
+}
+
+/*
+ * Check that an mpi is valid as a private key (SEC1 3.2)
+ */
+int ecp_check_privkey( const ecp_group *grp, const mpi *d )
+{
+    /* We want 1 <= d <= N-1 */
+    if ( mpi_cmp_int( d, 1 ) < 0 || mpi_cmp_mpi( d, &grp->N ) >= 0 )
+        return( POLARSSL_ERR_ECP_GENERIC );
+
+    return( 0 );
+}
+
+/*
  * Generate a keypair (SEC1 3.2.1)
  */
 int ecp_gen_keypair( const ecp_group *grp, mpi *d, ecp_point *Q,
diff --git a/library/error.c b/library/error.c
index 7042bbd..0a739b5 100644
--- a/library/error.c
+++ b/library/error.c
@@ -113,6 +113,10 @@
 #include "polarssl/pem.h"
 #endif
 
+#if defined(POLARSSL_PK_C)
+#include "polarssl/pk.h"
+#endif
+
 #if defined(POLARSSL_PKCS12_C)
 #include "polarssl/pkcs12.h"
 #endif
@@ -243,6 +247,11 @@
             snprintf( buf, buflen, "PEM - Bad input parameters to function" );
 #endif /* POLARSSL_PEM_C */
 
+#if defined(POLARSSL_PK_C)
+        if( use_ret == -(POLARSSL_ERR_PK_MALLOC_FAILED) )
+            snprintf( buf, buflen, "PK - Memory alloation failed" );
+#endif /* POLARSSL_PK_C */
+
 #if defined(POLARSSL_PKCS12_C)
         if( use_ret == -(POLARSSL_ERR_PKCS12_BAD_INPUT_DATA) )
             snprintf( buf, buflen, "PKCS12 - Bad input parameters to function" );
@@ -388,7 +397,7 @@
         if( use_ret == -(POLARSSL_ERR_X509_CERT_UNKNOWN_SIG_ALG) )
             snprintf( buf, buflen, "X509 - Signature algorithm (oid) is unsupported" );
         if( use_ret == -(POLARSSL_ERR_X509_UNKNOWN_PK_ALG) )
-            snprintf( buf, buflen, "X509 - Key algorithm is unsupported (only RSA is supported)" );
+            snprintf( buf, buflen, "X509 - Key algorithm is unsupported (only RSA and EC are supported)" );
         if( use_ret == -(POLARSSL_ERR_X509_CERT_SIG_MISMATCH) )
             snprintf( buf, buflen, "X509 - Certificate signature algorithms do not match. (see \\c ::x509_cert sig_oid)" );
         if( use_ret == -(POLARSSL_ERR_X509_CERT_VERIFY_FAILED) )
@@ -409,6 +418,8 @@
             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" );
+        if( use_ret == -(POLARSSL_ERR_X509_UNKNOWN_NAMED_CURVE) )
+            snprintf( buf, buflen, "X509 - Elliptic curve is unsupported (only NIST curves are supported)" );
 #endif /* POLARSSL_X509_PARSE_C */
 
         if( strlen( buf ) == 0 )
diff --git a/library/oid.c b/library/oid.c
index 5cd9a59..449b3e1 100644
--- a/library/oid.c
+++ b/library/oid.c
@@ -248,7 +248,6 @@
 
 FN_OID_TYPED_FROM_ASN1(oid_descriptor_t, ext_key_usage, oid_ext_key_usage);
 FN_OID_GET_ATTR1(oid_get_extended_key_usage, oid_descriptor_t, ext_key_usage, const char *, description);
-
 #endif /* POLARSSL_X509_PARSE_C || POLARSSL_X509_WRITE_C */
 
 #if defined(POLARSSL_MD_C)
@@ -312,7 +311,7 @@
 #endif /* POLARSSL_MD_C */
 
 /*
- * For PublicKeyInfo
+ * For PublicKeyInfo (PKCS1, RFC 5480)
  */
 typedef struct {
     oid_descriptor_t    descriptor;
@@ -326,6 +325,14 @@
         POLARSSL_PK_RSA,
     },
     {
+        { OID_EC_ALG_UNRESTRICTED,  "id-ecPublicKey",   "Generic EC key" },
+        POLARSSL_PK_ECKEY,
+    },
+    {
+        { OID_EC_ALG_ECDH,          "id-ecDH",          "EC key for ECDH" },
+        POLARSSL_PK_ECKEY_DH,
+    },
+    {
         { NULL, NULL, NULL },
         0,
     },
@@ -334,6 +341,45 @@
 FN_OID_TYPED_FROM_ASN1(oid_pk_alg_t, pk_alg, oid_pk_alg);
 FN_OID_GET_ATTR1(oid_get_pk_alg, oid_pk_alg_t, pk_alg, pk_type_t, pk_alg);
 
+/*
+ * For namedCurve (RFC 5480)
+ */
+typedef struct {
+    oid_descriptor_t    descriptor;
+    ecp_group_id        grp_id;
+} oid_ecp_grp_t;
+
+static const oid_ecp_grp_t oid_ecp_grp[] =
+{
+    {
+        { OID_EC_GRP_SECP192R1, "secp192r1",    "secp192r1" },
+        POLARSSL_ECP_DP_SECP192R1,
+    },
+    {
+        { OID_EC_GRP_SECP224R1, "secp224r1",    "secp224r1" },
+        POLARSSL_ECP_DP_SECP224R1,
+    },
+    {
+        { OID_EC_GRP_SECP256R1, "secp256r1",    "secp256r1" },
+        POLARSSL_ECP_DP_SECP256R1,
+    },
+    {
+        { OID_EC_GRP_SECP384R1, "secp384r1",    "secp384r1" },
+        POLARSSL_ECP_DP_SECP384R1,
+    },
+    {
+        { OID_EC_GRP_SECP521R1, "secp521r1",    "secp521r1" },
+        POLARSSL_ECP_DP_SECP521R1,
+    },
+    {
+        { NULL, NULL, NULL },
+        0,
+    },
+};
+
+FN_OID_TYPED_FROM_ASN1(oid_ecp_grp_t, grp_id, oid_ecp_grp);
+FN_OID_GET_ATTR1(oid_get_ec_grp, oid_ecp_grp_t, grp_id, ecp_group_id, grp_id);
+
 #if defined(POLARSSL_CIPHER_C)
 /*
  * For PKCS#5 PBES2 encryption algorithm
@@ -521,13 +567,14 @@
         SAFE_SNPRINTF();
     }
 
-    /* Prevent overflow in value. */
-    if( oid->len > sizeof(value) )
-        return( POLARSSL_ERR_DEBUG_BUF_TOO_SMALL );
-
     value = 0;
     for( i = 1; i < oid->len; i++ )
     {
+        /* Prevent overflow in value. */
+        unsigned int v = value << 7;
+        if ( v < value )
+            return( POLARSSL_ERR_DEBUG_BUF_TOO_SMALL );
+
         value <<= 7;
         value += oid->p[i] & 0x7F;
 
diff --git a/library/pem.c b/library/pem.c
index c4c5cb4..3f6d330 100644
--- a/library/pem.c
+++ b/library/pem.c
@@ -332,8 +332,13 @@
             pem_aes_decrypt( pem_iv, 32, buf, len, pwd, pwdlen );
 #endif /* POLARSSL_AES_C */
 
-        if( buf[0] != 0x30 || buf[1] != 0x82 ||
-            buf[4] != 0x02 || buf[5] != 0x01 )
+        /*
+         * The result will be ASN.1 starting with a SEQUENCE tag, with 1 to 3
+         * length bytes (allow 4 to be sure) in all known use cases.
+         *
+         * Use that as heurisitic to try detecting password mismatchs.
+         */
+        if( len <= 2 || buf[0] != 0x30 || buf[1] > 0x83 )
         {
             polarssl_free( buf );
             return( POLARSSL_ERR_PEM_PASSWORD_MISMATCH );
diff --git a/library/pk.c b/library/pk.c
new file mode 100644
index 0000000..71505ed
--- /dev/null
+++ b/library/pk.c
@@ -0,0 +1,117 @@
+/*
+ *  Public Key abstraction layer
+ *
+ *  Copyright (C) 2006-2013, Brainspark B.V.
+ *
+ *  This file is part of PolarSSL (http://www.polarssl.org)
+ *  Lead Maintainer: Paul Bakker <polarssl_maintainer at polarssl.org>
+ *
+ *  All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "polarssl/config.h"
+
+#include "polarssl/pk.h"
+
+#if defined(POLARSSL_RSA_C)
+#include "polarssl/rsa.h"
+#endif
+#if defined(POLARSSL_ECP_C)
+#include "polarssl/ecp.h"
+#endif
+
+#include <stdlib.h>
+
+/*
+ * Initialise a pk_context
+ */
+void pk_init( pk_context *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    ctx->type = POLARSSL_PK_NONE;
+    ctx->data = NULL;
+}
+
+/*
+ * Free (the components of) a pk_context
+ */
+void pk_free( pk_context *ctx )
+{
+    if( ctx == NULL )
+        return;
+
+    switch( ctx->type )
+    {
+        case POLARSSL_PK_NONE:
+            break;
+
+#if defined(POLARSSL_RSA_C)
+        case POLARSSL_PK_RSA:
+            rsa_free( ctx->data );
+            break;
+#endif
+
+#if defined(POLARSSL_ECP_C)
+        case POLARSSL_PK_ECKEY:
+        case POLARSSL_PK_ECKEY_DH:
+            ecp_keypair_free( ctx->data );
+            break;
+#endif
+    }
+
+    free( ctx-> data );
+
+    ctx->type = POLARSSL_PK_NONE;
+    ctx->data = NULL;
+}
+
+/*
+ * Set a pk_context to a given type
+ */
+int pk_set_type( pk_context *ctx, pk_type_t type )
+{
+    size_t size = 0;
+
+    switch( type )
+    {
+#if defined(POLARSSL_RSA_C)
+        case POLARSSL_PK_RSA:
+            size = sizeof( rsa_context );
+            break;
+#endif
+
+#if defined(POLARSSL_ECP_C)
+        case POLARSSL_PK_ECKEY:
+        case POLARSSL_PK_ECKEY_DH:
+            size = sizeof( ecp_keypair );
+            break;
+#endif
+
+        case POLARSSL_PK_NONE:
+            ; /* Should not happen */
+    }
+
+    if( ( ctx->data = malloc( size ) ) == NULL )
+        return( POLARSSL_ERR_PK_MALLOC_FAILED );
+
+    memset( ctx->data, 0, size );
+    ctx->type = type;
+
+    return( 0 );
+}
diff --git a/library/x509parse.c b/library/x509parse.c
index ea3a24a..c5f9049 100644
--- a/library/x509parse.c
+++ b/library/x509parse.c
@@ -164,15 +164,105 @@
  *  AlgorithmIdentifier  ::=  SEQUENCE  {
  *       algorithm               OBJECT IDENTIFIER,
  *       parameters              ANY DEFINED BY algorithm OPTIONAL  }
+ *
+ * If params_end is NULL, then parameters must be absent or ANS.1 NULL
  */
 static int x509_get_alg( unsigned char **p,
                          const unsigned char *end,
-                         x509_buf *alg )
+                         x509_buf *alg, const unsigned char **params_end )
 {
     int ret;
+    size_t len;
 
-    if( ( ret = asn1_get_alg_null( p, end, alg ) ) != 0 )
+    if( params_end == NULL ) {
+        if( ( ret = asn1_get_alg_null( p, end, alg ) ) != 0 )
+            return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret );
+
+        return( 0 );
+    }
+
+    /* TODO: use asn1_get_alg */
+    if( ( ret = asn1_get_tag( p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
         return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret );
+    }
+
+    end = *p + len;
+    alg->tag = **p;
+
+    if( ( ret = asn1_get_tag( p, end, &alg->len, ASN1_OID ) ) != 0 )
+        return( POLARSSL_ERR_X509_CERT_INVALID_ALG + ret );
+
+    alg->p = *p;
+    *p += alg->len;
+
+    *params_end = end;
+    return( 0 );
+}
+
+/* Get an EC group id from an ECParameters buffer
+ *
+ * ECParameters ::= CHOICE {
+ *   namedCurve         OBJECT IDENTIFIER
+ *   -- implicitCurve   NULL
+ *   -- specifiedCurve  SpecifiedECDomain
+ * }
+ */
+static int x509_get_ecparams( unsigned char **p, const unsigned char *end,
+                              ecp_group_id *grp_id )
+{
+    int ret;
+    x509_buf curve;
+
+    curve.tag = **p;
+
+    if( ( ret = asn1_get_tag( p, end, &curve.len, ASN1_OID ) ) != 0 )
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+
+    curve.p = *p;
+    *p += curve.len;
+
+    if( *p != end )
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT +
+                POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    if( ( ret = oid_get_ec_grp( &curve, grp_id ) ) != 0 )
+        return( POLARSSL_ERR_X509_UNKNOWN_NAMED_CURVE );
+
+    return( 0 );
+}
+
+/*
+ * subjectPublicKey  BIT STRING
+ * -- which, in our case, contains
+ * ECPoint ::= octet string (not ASN.1)
+ */
+static int x509_get_subpubkey_ec( unsigned char **p, const unsigned char *end,
+                                  const ecp_group *grp, ecp_point *pt )
+{
+    int ret;
+    size_t len;
+
+    if( ( ret = asn1_get_tag( p, end, &len, ASN1_BIT_STRING ) ) != 0 )
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+
+    if( *p + len != end )
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT +
+                POLARSSL_ERR_ASN1_LENGTH_MISMATCH );
+
+    /*
+     * First byte in the content of BIT STRING is the nummber of padding bit.
+     * Here it is always 0 since ECPoint is an octet string, so skip it.
+     */
+    ++*p;
+    --len;
+
+    if( ( ret = ecp_point_read_binary( grp, pt,
+                    (const unsigned char *) *p, len ) ) != 0 )
+    {
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+    }
 
     return( 0 );
 }
@@ -422,7 +512,12 @@
      * only RSA public keys handled at this time
      */
     if( oid_get_pk_alg( pk_alg_oid, &pk_alg ) != 0 )
+    {
         return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG );
+    }
+
+    if (pk_alg != POLARSSL_PK_RSA )
+        return( POLARSSL_ERR_X509_CERT_INVALID_ALG );
 
     if( ( ret = asn1_get_tag( p, end, &len, ASN1_BIT_STRING ) ) != 0 )
         return( POLARSSL_ERR_X509_CERT_INVALID_PUBKEY + ret );
@@ -1146,9 +1241,9 @@
      *
      * signature            AlgorithmIdentifier
      */
-    if( ( ret = x509_get_version( &p, end, &crt->version ) ) != 0 ||
-        ( ret = x509_get_serial(  &p, end, &crt->serial  ) ) != 0 ||
-        ( ret = x509_get_alg(  &p, end, &crt->sig_oid1   ) ) != 0 )
+    if( ( ret = x509_get_version( &p, end, &crt->version    ) ) != 0 ||
+        ( ret = x509_get_serial(  &p, end, &crt->serial     ) ) != 0 ||
+        ( ret = x509_get_alg( &p, end, &crt->sig_oid1, NULL ) ) != 0 )
     {
         x509_free( crt );
         return( ret );
@@ -1300,7 +1395,7 @@
      *  signatureAlgorithm   AlgorithmIdentifier,
      *  signatureValue       BIT STRING
      */
-    if( ( ret = x509_get_alg( &p, end, &crt->sig_oid2 ) ) != 0 )
+    if( ( ret = x509_get_alg( &p, end, &crt->sig_oid2, NULL ) ) != 0 )
     {
         x509_free( crt );
         return( ret );
@@ -1623,7 +1718,7 @@
      * signature            AlgorithmIdentifier
      */
     if( ( ret = x509_crl_get_version( &p, end, &crl->version ) ) != 0 ||
-        ( ret = x509_get_alg(  &p, end, &crl->sig_oid1   ) ) != 0 )
+        ( ret = x509_get_alg(  &p, end, &crl->sig_oid1, NULL ) ) != 0 )
     {
         x509_crl_free( crl );
         return( ret );
@@ -1728,7 +1823,7 @@
      *  signatureAlgorithm   AlgorithmIdentifier,
      *  signatureValue       BIT STRING
      */
-    if( ( ret = x509_get_alg( &p, end, &crl->sig_oid2 ) ) != 0 )
+    if( ( ret = x509_get_alg( &p, end, &crl->sig_oid2, NULL ) ) != 0 )
     {
         x509_crl_free( crl );
         return( ret );
@@ -1817,7 +1912,7 @@
     size_t n;
     unsigned char *buf;
 
-    if ( (ret = load_file( path, &buf, &n ) ) != 0 )
+    if ( ( ret = load_file( path, &buf, &n ) ) != 0 )
         return( ret );
 
     ret = x509parse_crt( chain, buf, n );
@@ -1931,7 +2026,7 @@
     size_t n;
     unsigned char *buf;
 
-    if ( (ret = load_file( path, &buf, &n ) ) != 0 )
+    if ( ( ret = load_file( path, &buf, &n ) ) != 0 )
         return( ret );
 
     ret = x509parse_crl( chain, buf, n );
@@ -1945,19 +2040,19 @@
 /*
  * Load and parse a private RSA key
  */
-int x509parse_keyfile( rsa_context *rsa, const char *path, const char *pwd )
+int x509parse_keyfile_rsa( rsa_context *rsa, const char *path, const char *pwd )
 {
     int ret;
     size_t n;
     unsigned char *buf;
 
-    if ( (ret = load_file( path, &buf, &n ) ) != 0 )
+    if ( ( ret = load_file( path, &buf, &n ) ) != 0 )
         return( ret );
 
     if( pwd == NULL )
-        ret = x509parse_key( rsa, buf, n, NULL, 0 );
+        ret = x509parse_key_rsa( rsa, buf, n, NULL, 0 );
     else
-        ret = x509parse_key( rsa, buf, n,
+        ret = x509parse_key_rsa( rsa, buf, n,
                 (const unsigned char *) pwd, strlen( pwd ) );
 
     memset( buf, 0, n + 1 );
@@ -1969,7 +2064,28 @@
 /*
  * Load and parse a public RSA key
  */
-int x509parse_public_keyfile( rsa_context *rsa, const char *path )
+int x509parse_public_keyfile_rsa( rsa_context *rsa, const char *path )
+{
+    int ret;
+    size_t n;
+    unsigned char *buf;
+
+    if ( ( ret = load_file( path, &buf, &n ) ) != 0 )
+        return( ret );
+
+    ret = x509parse_public_key_rsa( rsa, buf, n );
+
+    memset( buf, 0, n + 1 );
+    polarssl_free( buf );
+
+    return( ret );
+}
+
+/*
+ * Load and parse a private key
+ */
+int x509parse_keyfile( pk_context *ctx,
+                       const char *path, const char *pwd )
 {
     int ret;
     size_t n;
@@ -1978,13 +2094,38 @@
     if ( (ret = load_file( path, &buf, &n ) ) != 0 )
         return( ret );
 
-    ret = x509parse_public_key( rsa, buf, n );
+    if( pwd == NULL )
+        ret = x509parse_key( ctx, buf, n, NULL, 0 );
+    else
+        ret = x509parse_key( ctx, buf, n,
+                (const unsigned char *) pwd, strlen( pwd ) );
 
     memset( buf, 0, n + 1 );
-    polarssl_free( buf );
+    free( buf );
 
     return( ret );
 }
+
+/*
+ * Load and parse a public key
+ */
+int x509parse_public_keyfile( pk_context *ctx, const char *path )
+{
+    int ret;
+    size_t n;
+    unsigned char *buf;
+
+    if ( (ret = load_file( path, &buf, &n ) ) != 0 )
+        return( ret );
+
+    ret = x509parse_public_key( ctx, buf, n );
+
+    memset( buf, 0, n + 1 );
+    free( buf );
+
+    return( ret );
+}
+
 #endif /* POLARSSL_FS_IO */
 
 /*
@@ -2032,7 +2173,7 @@
 
     if( rsa->ver != 0 )
     {
-        return( POLARSSL_ERR_X509_KEY_INVALID_VERSION + ret );
+        return( POLARSSL_ERR_X509_KEY_INVALID_VERSION );
     }
 
     if( ( ret = asn1_get_mpi( &p, end, &rsa->N  ) ) != 0 ||
@@ -2120,7 +2261,12 @@
      * only RSA keys handled at this time
      */
     if( oid_get_pk_alg( &pk_alg_oid, &pk_alg ) != 0 )
+    {
         return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG );
+    }
+
+    if (pk_alg != POLARSSL_PK_RSA )
+        return( POLARSSL_ERR_X509_CERT_INVALID_ALG );
 
     /*
      * Get the OCTET STRING and parse the PKCS#1 format inside
@@ -2143,26 +2289,23 @@
 }
 
 /*
- * Parse an encrypted PKCS#8 encoded private RSA key
+ * Decrypt the content of a PKCS#8 EncryptedPrivateKeyInfo
  */
-static int x509parse_key_pkcs8_encrypted_der(
-                                    rsa_context *rsa,
-                                    const unsigned char *key,
-                                    size_t keylen,
-                                    const unsigned char *pwd,
-                                    size_t pwdlen )
+static int x509parse_pkcs8_decrypt( unsigned char *buf, size_t buflen,
+                                    size_t *used_len,
+                                    const unsigned char *key, size_t keylen,
+                                    const unsigned char *pwd, size_t pwdlen )
 {
     int ret;
     size_t len;
     unsigned char *p, *end;
     x509_buf pbe_alg_oid, pbe_params;
-    unsigned char buf[2048];
 #if defined(POLARSSL_PKCS12_C)
     cipher_type_t cipher_alg;
     md_type_t md_alg;
 #endif
 
-    memset(buf, 0, 2048);
+    memset(buf, 0, buflen);
 
     p = (unsigned char *) key;
     end = p + keylen;
@@ -2198,8 +2341,7 @@
     if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 )
         return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
 
-    // buf has been sized to 2048 bytes
-    if( len > 2048 )
+    if( len > buflen )
         return( POLARSSL_ERR_X509_INVALID_INPUT );
 
     /*
@@ -2252,14 +2394,37 @@
 #endif /* POLARSSL_PKCS5_C */
         return( POLARSSL_ERR_X509_FEATURE_UNAVAILABLE );
 
-    return x509parse_key_pkcs8_unencrypted_der( rsa, buf, len );
+    *used_len = len;
+    return( 0 );
+}
+
+/*
+ * Parse an encrypted PKCS#8 encoded private RSA key
+ */
+static int x509parse_key_pkcs8_encrypted_der(
+                                    rsa_context *rsa,
+                                    const unsigned char *key, size_t keylen,
+                                    const unsigned char *pwd, size_t pwdlen )
+{
+    int ret;
+    unsigned char buf[2048];
+    size_t len = 0;
+
+    if( ( ret = x509parse_pkcs8_decrypt( buf, sizeof( buf ), &len,
+            key, keylen, pwd, pwdlen ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    return( x509parse_key_pkcs8_unencrypted_der( rsa, buf, len ) );
 }
 
 /*
  * Parse a private RSA key
  */
-int x509parse_key( rsa_context *rsa, const unsigned char *key, size_t keylen,
-                                     const unsigned char *pwd, size_t pwdlen )
+int x509parse_key_rsa( rsa_context *rsa,
+                       const unsigned char *key, size_t keylen,
+                       const unsigned char *pwd, size_t pwdlen )
 {
     int ret;
 
@@ -2330,12 +2495,13 @@
     ((void) pwdlen);
 #endif /* POLARSSL_PEM_C */
 
-    // At this point we only know it's not a PEM formatted key. Could be any
-    // of the known DER encoded private key formats
-    //
-    // We try the different DER format parsers to see if one passes without
-    // error
-    //
+    /*
+    * At this point we only know it's not a PEM formatted key. Could be any
+    * of the known DER encoded private key formats
+    *
+    * We try the different DER format parsers to see if one passes without
+    * error
+    */
     if( ( ret = x509parse_key_pkcs8_encrypted_der( rsa, key, keylen,
                                                    pwd, pwdlen ) ) == 0 )
     {
@@ -2365,7 +2531,8 @@
 /*
  * Parse a public RSA key
  */
-int x509parse_public_key( rsa_context *rsa, const unsigned char *key, size_t keylen )
+int x509parse_public_key_rsa( rsa_context *rsa,
+                              const unsigned char *key, size_t keylen )
 {
     int ret;
     size_t len;
@@ -2453,6 +2620,500 @@
     return( 0 );
 }
 
+#if defined(POLARSSL_ECP_C)
+/*
+ * Parse a SEC1 encoded private EC key
+ */
+static int x509parse_key_sec1_der( ecp_keypair *eck,
+                                   const unsigned char *key,
+                                   size_t keylen )
+{
+    int ret;
+    int version;
+    size_t len;
+    ecp_group_id grp_id;
+    unsigned char *p = (unsigned char *) key;
+    unsigned char *end = p + keylen;
+
+    /*
+     * RFC 5915, orf SEC1 Appendix C.4
+     *
+     * ECPrivateKey ::= SEQUENCE {
+     *      version        INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+     *      privateKey     OCTET STRING,
+     *      parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
+     *      publicKey  [1] BIT STRING OPTIONAL
+     *    }
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+    }
+
+    end = p + len;
+
+    if( ( ret = asn1_get_int( &p, end, &version ) ) != 0 )
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+
+    if( version != 1 )
+        return( POLARSSL_ERR_X509_KEY_INVALID_VERSION );
+
+    if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 )
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+
+    if( ( ret = mpi_read_binary( &eck->d, p, len ) ) != 0 )
+    {
+        ecp_keypair_free( eck );
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+    }
+
+    p += len;
+
+    /*
+     * Is 'parameters' present?
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+                    ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 0 ) ) == 0 )
+    {
+        if( ( ret = x509_get_ecparams( &p, p + len, &grp_id) ) != 0 )
+            return( ret );
+
+        /*
+         * If we're wrapped in a bigger structure (eg PKCS#8), grp may have been
+         * defined externally. In this case, make sure both definitions match.
+         */
+        if( eck->grp.id != 0 )
+        {
+            if( eck->grp.id != grp_id )
+            {
+                ecp_keypair_free( eck );
+                return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+            }
+        }
+        else
+        {
+            if( ( ret = ecp_use_known_dp( &eck->grp, grp_id ) ) != 0 )
+            {
+                ecp_keypair_free( eck );
+                return( ret );
+            }
+        }
+    }
+    else if ( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+    {
+        ecp_keypair_free( eck );
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+    }
+
+    /*
+     * Is 'publickey' present?
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+                    ASN1_CONTEXT_SPECIFIC | ASN1_CONSTRUCTED | 1 ) ) == 0 )
+    {
+        if( ( ret = x509_get_subpubkey_ec( &p, p + len, &eck->grp, &eck->Q ) )
+                != 0 )
+        {
+            ecp_keypair_free( eck );
+            return( ret );
+        }
+
+        if( ( ret = ecp_check_pubkey( &eck->grp, &eck->Q ) ) != 0 )
+        {
+            ecp_keypair_free( eck );
+            return( ret );
+        }
+    }
+    else if ( ret != POLARSSL_ERR_ASN1_UNEXPECTED_TAG )
+    {
+        ecp_keypair_free( eck );
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+    }
+
+    if( ( ret = ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 )
+    {
+        ecp_keypair_free( eck );
+        return( ret );
+    }
+
+    return 0;
+}
+
+/*
+ * Parse an unencrypted PKCS#8 encoded private EC key
+ */
+static int x509parse_key_pkcs8_unencrypted_der_ec(
+                                    ecp_keypair *eck,
+                                    const unsigned char* key,
+                                    size_t keylen )
+{
+    int ret, version;
+    size_t len;
+    x509_buf pk_alg_oid;
+    ecp_group_id grp_id;
+    const unsigned char *params_end;
+    unsigned char *p = (unsigned char *) key;
+    unsigned char *end = p + keylen;
+    pk_type_t pk_alg = POLARSSL_PK_NONE;
+
+    /*
+     * This function parses the PrivatKeyInfo object (PKCS#8 v1.2 = RFC 5208)
+     *
+     *    PrivateKeyInfo ::= SEQUENCE {
+     *      version                   Version,
+     *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
+     *      privateKey                PrivateKey,
+     *      attributes           [0]  IMPLICIT Attributes OPTIONAL }
+     *
+     *    Version ::= INTEGER
+     *    PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+     *    PrivateKey ::= OCTET STRING
+     *
+     *  The PrivateKey OCTET STRING is a SEC1 ECPrivateKey
+     */
+
+    if( ( ret = asn1_get_tag( &p, end, &len,
+            ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+    }
+
+    end = p + len;
+
+    if( ( ret = asn1_get_int( &p, end, &version ) ) != 0 )
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+
+    if( version != 0 )
+        return( POLARSSL_ERR_X509_KEY_INVALID_VERSION + ret );
+
+    if( ( ret = x509_get_alg( &p, end, &pk_alg_oid, &params_end ) ) != 0 )
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+
+    if( oid_get_pk_alg( &pk_alg_oid, &pk_alg ) != 0 )
+        return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG );
+
+    if( pk_alg != POLARSSL_PK_ECKEY && pk_alg != POLARSSL_PK_ECKEY_DH )
+        return( POLARSSL_ERR_X509_CERT_INVALID_ALG );
+
+    if( pk_alg == POLARSSL_PK_ECKEY_DH )
+        eck->alg = POLARSSL_ECP_KEY_ALG_ECDH;
+
+    if( ( ret = x509_get_ecparams( &p, params_end, &grp_id ) ) != 0 )
+    {
+        ecp_keypair_free( eck );
+        return( ret );
+    }
+
+    if( ( ret = ecp_use_known_dp( &eck->grp, grp_id ) ) != 0 )
+    {
+        ecp_keypair_free( eck );
+        return( ret );
+    }
+
+    if( ( ret = asn1_get_tag( &p, end, &len, ASN1_OCTET_STRING ) ) != 0 )
+    {
+        ecp_keypair_free( eck );
+        return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT + ret );
+    }
+
+    if( ( ret = x509parse_key_sec1_der( eck, p, len ) ) != 0 )
+    {
+        ecp_keypair_free( eck );
+        return( ret );
+    }
+
+    if( ( ret = ecp_check_privkey( &eck->grp, &eck->d ) ) != 0 )
+    {
+        ecp_keypair_free( eck );
+        return( ret );
+    }
+
+    return 0;
+}
+
+/*
+ * Parse an encrypted PKCS#8 encoded private EC key
+ */
+static int x509parse_key_pkcs8_encrypted_der_ec(
+                                    ecp_keypair *eck,
+                                    const unsigned char *key, size_t keylen,
+                                    const unsigned char *pwd, size_t pwdlen )
+{
+    int ret;
+    unsigned char buf[2048];
+    size_t len = 0;
+
+    if( ( ret = x509parse_pkcs8_decrypt( buf, sizeof( buf ), &len,
+            key, keylen, pwd, pwdlen ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    return( x509parse_key_pkcs8_unencrypted_der_ec( eck, buf, len ) );
+}
+
+/*
+ * Parse a private EC key
+ */
+static int x509parse_key_ec( ecp_keypair *eck,
+                             const unsigned char *key, size_t keylen,
+                             const unsigned char *pwd, size_t pwdlen )
+{
+    int ret;
+
+#if defined(POLARSSL_PEM_C)
+    size_t len;
+    pem_context pem;
+
+    pem_init( &pem );
+    ret = pem_read_buffer( &pem,
+                           "-----BEGIN EC PRIVATE KEY-----",
+                           "-----END EC PRIVATE KEY-----",
+                           key, pwd, pwdlen, &len );
+    if( ret == 0 )
+    {
+        if( ( ret = x509parse_key_sec1_der( eck, pem.buf, pem.buflen ) ) != 0 )
+        {
+            ecp_keypair_free( eck );
+        }
+
+        pem_free( &pem );
+        return( ret );
+    }
+    else if( ret == POLARSSL_ERR_PEM_PASSWORD_MISMATCH )
+        return( POLARSSL_ERR_X509_PASSWORD_MISMATCH );
+    else if( ret == POLARSSL_ERR_PEM_PASSWORD_REQUIRED )
+        return( POLARSSL_ERR_X509_PASSWORD_REQUIRED );
+    else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+        return( ret );
+
+    ret = pem_read_buffer( &pem,
+                           "-----BEGIN PRIVATE KEY-----",
+                           "-----END PRIVATE KEY-----",
+                           key, NULL, 0, &len );
+    if( ret == 0 )
+    {
+        if( ( ret = x509parse_key_pkcs8_unencrypted_der_ec( eck,
+                                                pem.buf, pem.buflen ) ) != 0 )
+        {
+            ecp_keypair_free( eck );
+        }
+
+        pem_free( &pem );
+        return( ret );
+    }
+    else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+        return( ret );
+
+    ret = pem_read_buffer( &pem,
+                           "-----BEGIN ENCRYPTED PRIVATE KEY-----",
+                           "-----END ENCRYPTED PRIVATE KEY-----",
+                           key, NULL, 0, &len );
+    if( ret == 0 )
+    {
+        if( ( ret = x509parse_key_pkcs8_encrypted_der_ec( eck,
+                                                pem.buf, pem.buflen,
+                                                pwd, pwdlen ) ) != 0 )
+        {
+            ecp_keypair_free( eck );
+        }
+
+        pem_free( &pem );
+        return( ret );
+    }
+    else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+        return( ret );
+#else
+    ((void) pwd);
+    ((void) pwdlen);
+#endif /* POLARSSL_PEM_C */
+
+    /*
+    * At this point we only know it's not a PEM formatted key. Could be any
+    * of the known DER encoded private key formats
+    *
+    * We try the different DER format parsers to see if one passes without
+    * error
+    */
+    if( ( ret = x509parse_key_pkcs8_encrypted_der_ec( eck, key, keylen,
+                                                      pwd, pwdlen ) ) == 0 )
+    {
+        return( 0 );
+    }
+
+    ecp_keypair_free( eck );
+
+    if( ret == POLARSSL_ERR_X509_PASSWORD_MISMATCH )
+    {
+        return( ret );
+    }
+
+    if( ( ret = x509parse_key_pkcs8_unencrypted_der_ec( eck,
+                                                        key, keylen ) ) == 0 )
+        return( 0 );
+
+    ecp_keypair_free( eck );
+
+    if( ( ret = x509parse_key_sec1_der( eck, key, keylen ) ) == 0 )
+        return( 0 );
+
+    ecp_keypair_free( eck );
+
+    return( POLARSSL_ERR_X509_KEY_INVALID_FORMAT );
+}
+
+/*
+ * Parse a public EC key in RFC 5480 format, der-encoded
+ */
+static int x509parse_public_key_ec_der( ecp_keypair *key,
+                                        const unsigned char *buf, size_t len )
+{
+    int ret;
+    ecp_group_id grp_id;
+    x509_buf alg_oid;
+    pk_type_t alg = POLARSSL_PK_NONE;
+    unsigned char *p = (unsigned char *) buf;
+    unsigned char *end = p + len;
+    const unsigned char *params_end;
+    /*
+     * SubjectPublicKeyInfo  ::=  SEQUENCE  {
+     *   algorithm         AlgorithmIdentifier,
+     *   subjectPublicKey  BIT STRING
+     * }
+     * -- algorithm parameters are ECParameters
+     * -- subjectPublicKey is an ECPoint
+     */
+    if( ( ret = asn1_get_tag( &p, end, &len,
+                    ASN1_CONSTRUCTED | ASN1_SEQUENCE ) ) != 0 )
+    {
+        return( POLARSSL_ERR_X509_CERT_INVALID_FORMAT + ret );
+    }
+
+    if( ( ret = x509_get_alg( &p, end, &alg_oid, &params_end ) ) != 0 )
+        return( ret );
+
+    if( oid_get_pk_alg( &alg_oid, &alg ) != 0 )
+        return( POLARSSL_ERR_X509_UNKNOWN_PK_ALG );
+
+    if( alg != POLARSSL_PK_ECKEY && alg != POLARSSL_PK_ECKEY_DH )
+        return( POLARSSL_ERR_X509_CERT_INVALID_ALG );
+
+    if( alg == POLARSSL_PK_ECKEY_DH )
+        key->alg = POLARSSL_ECP_KEY_ALG_ECDH;
+
+    if( ( ret = x509_get_ecparams( &p, params_end, &grp_id ) ) != 0 )
+        return( ret );
+
+    if( ( ret = ecp_use_known_dp( &key->grp, grp_id ) ) != 0 )
+        return( ret );
+
+    if( ( ret = x509_get_subpubkey_ec( &p, end, &key->grp, &key->Q ) ) != 0 )
+    {
+        return( ret );
+    }
+
+    return( 0 );
+}
+
+/*
+ * Parse a public EC key
+ */
+static int x509parse_public_key_ec( ecp_keypair *eckey,
+                                    const unsigned char *key, size_t keylen )
+{
+    int ret;
+#if defined(POLARSSL_PEM_C)
+    size_t len;
+    pem_context pem;
+
+    pem_init( &pem );
+    ret = pem_read_buffer( &pem,
+            "-----BEGIN PUBLIC KEY-----",
+            "-----END PUBLIC KEY-----",
+            key, NULL, 0, &len );
+
+    if( ret == 0 )
+    {
+        /*
+         * Was PEM encoded
+         */
+        key = pem.buf;
+        keylen = pem.buflen;
+    }
+    else if( ret != POLARSSL_ERR_PEM_NO_HEADER_FOOTER_PRESENT )
+    {
+        pem_free( &pem );
+        return( ret );
+    }
+#endif
+
+    if( ( ret = x509parse_public_key_ec_der ( eckey, key, keylen )  ) != 0 ||
+        ( ret = ecp_check_pubkey( &eckey->grp, &eckey->Q )          ) != 0 )
+    {
+        ecp_keypair_free( eckey );
+    }
+
+#if defined(POLARSSL_PEM_C)
+    pem_free( &pem );
+#endif
+
+    return( ret );
+}
+#endif /* defined(POLARSSL_ECP_C) */
+
+/*
+ * Parse a private key
+ */
+int x509parse_key( pk_context *ctx,
+                   const unsigned char *key, size_t keylen,
+                   const unsigned char *pwd, size_t pwdlen )
+{
+    int ret;
+
+    if ( ( ret = pk_set_type( ctx, POLARSSL_PK_RSA ) ) != 0 )
+        return( ret );
+
+    if( ( ret = x509parse_key_rsa( ctx->data, key, keylen, pwd, pwdlen ) )
+            == 0 )
+    {
+        return( 0 );
+    }
+
+    if ( ( ret = pk_set_type( ctx, POLARSSL_PK_ECKEY ) ) != 0 )
+        return( ret );
+
+    if( ( ret = x509parse_key_ec( ctx->data, key, keylen, pwd, pwdlen ) ) == 0 )
+    {
+        return( 0 );
+    }
+
+    return( POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT );
+}
+
+/*
+ * Parse a public key
+ */
+int x509parse_public_key( pk_context *ctx,
+                          const unsigned char *key, size_t keylen )
+{
+    int ret;
+
+    if ( ( ret = pk_set_type( ctx, POLARSSL_PK_RSA ) ) != 0 )
+        return( ret );
+
+    if( ( ret = x509parse_public_key_rsa( ctx->data, key, keylen ) ) == 0 )
+        return( 0 );
+
+    if ( ( ret = pk_set_type( ctx, POLARSSL_PK_ECKEY ) ) != 0 )
+        return( ret );
+
+    if( ( ret = x509parse_public_key_ec( ctx->data, key, keylen ) ) == 0 )
+        return( 0 );
+
+    return( POLARSSL_ERR_X509_CERT_UNKNOWN_FORMAT );
+}
+
 #if defined(POLARSSL_DHM_C)
 /*
  * Parse DHM parameters
@@ -2539,7 +3200,7 @@
 
 #if defined(POLARSSL_FS_IO)
 /*
- * Load and parse a private RSA key
+ * Load and parse DHM parameters
  */
 int x509parse_dhmfile( dhm_context *dhm, const char *path )
 {
@@ -3562,7 +4223,7 @@
 
     rsa_init( &rsa, RSA_PKCS_V15, 0 );
 
-    if( ( ret = x509parse_key( &rsa,
+    if( ( ret = x509parse_key_rsa( &rsa,
                     (const unsigned char *) test_ca_key, i,
                     (const unsigned char *) test_ca_pwd, j ) ) != 0 )
     {
diff --git a/programs/pkey/key_app.c b/programs/pkey/key_app.c
index 2f906c4..bea996a 100644
--- a/programs/pkey/key_app.c
+++ b/programs/pkey/key_app.c
@@ -164,14 +164,14 @@
         printf( "\n  . Loading the private key ..." );
         fflush( stdout );
 
-        ret = x509parse_keyfile( &rsa, opt.filename, opt.password );
+        ret = x509parse_keyfile_rsa( &rsa, opt.filename, opt.password );
 
         if( ret != 0 )
         {
 #ifdef POLARSSL_ERROR_C
             polarssl_strerror( ret, buf, 1024 );
 #endif
-            printf( " failed\n  !  x509parse_key returned %d - %s\n\n", ret, buf );
+            printf( " failed\n  !  x509parse_key_rsa returned %d - %s\n\n", ret, buf );
             rsa_free( &rsa );
             goto exit;
         }
@@ -199,14 +199,14 @@
         printf( "\n  . Loading the public key ..." );
         fflush( stdout );
 
-        ret = x509parse_public_keyfile( &rsa, opt.filename );
+        ret = x509parse_public_keyfile_rsa( &rsa, opt.filename );
 
         if( ret != 0 )
         {
 #ifdef POLARSSL_ERROR_C
             polarssl_strerror( ret, buf, 1024 );
 #endif
-            printf( " failed\n  !  x509parse_public_key returned %d - %s\n\n", ret, buf );
+            printf( " failed\n  !  x509parse_public_key_rsa returned %d - %s\n\n", ret, buf );
             rsa_free( &rsa );
             goto exit;
         }
diff --git a/programs/pkey/key_app_writer.c b/programs/pkey/key_app_writer.c
index feb2ecc..88cb907 100644
--- a/programs/pkey/key_app_writer.c
+++ b/programs/pkey/key_app_writer.c
@@ -238,14 +238,14 @@
         printf( "\n  . Loading the private key ..." );
         fflush( stdout );
 
-        ret = x509parse_keyfile( &rsa, opt.filename, NULL );
+        ret = x509parse_keyfile_rsa( &rsa, opt.filename, NULL );
 
         if( ret != 0 )
         {
 #ifdef POLARSSL_ERROR_C
             polarssl_strerror( ret, buf, 1024 );
 #endif
-            printf( " failed\n  !  x509parse_key returned %d - %s\n\n", ret, buf );
+            printf( " failed\n  !  x509parse_key_rsa returned %d - %s\n\n", ret, buf );
             rsa_free( &rsa );
             goto exit;
         }
@@ -274,14 +274,14 @@
         printf( "\n  . Loading the public key ..." );
         fflush( stdout );
 
-        ret = x509parse_public_keyfile( &rsa, opt.filename );
+        ret = x509parse_public_keyfile_rsa( &rsa, opt.filename );
 
         if( ret != 0 )
         {
 #ifdef POLARSSL_ERROR_C
             polarssl_strerror( ret, buf, 1024 );
 #endif
-            printf( " failed\n  !  x509parse_public_key returned %d - %s\n\n", ret, buf );
+            printf( " failed\n  !  x509parse_public_key_rsa returned %d - %s\n\n", ret, buf );
             rsa_free( &rsa );
             goto exit;
         }
diff --git a/programs/pkey/rsa_sign_pss.c b/programs/pkey/rsa_sign_pss.c
index 8238708..e848f54 100644
--- a/programs/pkey/rsa_sign_pss.c
+++ b/programs/pkey/rsa_sign_pss.c
@@ -101,7 +101,7 @@
 
     rsa_init( &rsa, RSA_PKCS_V21, POLARSSL_MD_SHA1 );
 
-    if( ( ret = x509parse_keyfile( &rsa, argv[1], "" ) ) != 0 )
+    if( ( ret = x509parse_keyfile_rsa( &rsa, argv[1], "" ) ) != 0 )
     {
         ret = 1;
         printf( " failed\n  ! Could not open '%s'\n", argv[1] );
diff --git a/programs/pkey/rsa_verify_pss.c b/programs/pkey/rsa_verify_pss.c
index b44daa0..00d7378 100644
--- a/programs/pkey/rsa_verify_pss.c
+++ b/programs/pkey/rsa_verify_pss.c
@@ -83,9 +83,9 @@
 
     rsa_init( &rsa, RSA_PKCS_V21, POLARSSL_MD_SHA1 );
 
-    if( ( ret = x509parse_public_keyfile( &rsa, argv[1] ) ) != 0 )
+    if( ( ret = x509parse_public_keyfile_rsa( &rsa, argv[1] ) ) != 0 )
     {
-        printf( " failed\n  ! x509parse_public_key returned %d\n\n", ret );
+        printf( " failed\n  ! x509parse_public_key_rsa returned %d\n\n", ret );
         goto exit;
     }
 
diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c
index 1ddb86d..036cc67 100644
--- a/programs/ssl/ssl_client2.c
+++ b/programs/ssl/ssl_client2.c
@@ -533,11 +533,11 @@
 
 #if defined(POLARSSL_FS_IO)
     if( strlen( opt.key_file ) )
-        ret = x509parse_keyfile( &rsa, opt.key_file, "" );
+        ret = x509parse_keyfile_rsa( &rsa, opt.key_file, "" );
     else
 #endif
 #if defined(POLARSSL_CERTS_C)
-        ret = x509parse_key( &rsa, (const unsigned char *) test_cli_key,
+        ret = x509parse_key_rsa( &rsa, (const unsigned char *) test_cli_key,
                 strlen( test_cli_key ), NULL, 0 );
 #else
     {
@@ -547,7 +547,7 @@
 #endif
     if( ret != 0 )
     {
-        printf( " failed\n  !  x509parse_key returned -0x%x\n\n", -ret );
+        printf( " failed\n  !  x509parse_key_rsa returned -0x%x\n\n", -ret );
         goto exit;
     }
 
diff --git a/programs/ssl/ssl_fork_server.c b/programs/ssl/ssl_fork_server.c
index e021ebb..986458b 100644
--- a/programs/ssl/ssl_fork_server.c
+++ b/programs/ssl/ssl_fork_server.c
@@ -139,7 +139,7 @@
     /*
      * This demonstration program uses embedded test certificates.
      * Instead, you may want to use x509parse_crtfile() to read the
-     * server and CA certificates, as well as x509parse_keyfile().
+     * server and CA certificates, as well as x509parse_keyfile_rsa().
      */
     ret = x509parse_crt( &srvcert, (const unsigned char *) test_srv_crt,
                          strlen( test_srv_crt ) );
@@ -158,11 +158,11 @@
     }
 
     rsa_init( &rsa, RSA_PKCS_V15, 0 );
-    ret =  x509parse_key( &rsa, (const unsigned char *) test_srv_key,
+    ret =  x509parse_key_rsa( &rsa, (const unsigned char *) test_srv_key,
                           strlen( test_srv_key ), NULL, 0 );
     if( ret != 0 )
     {
-        printf( " failed\n  !  x509parse_key returned %d\n\n", ret );
+        printf( " failed\n  !  x509parse_key_rsa returned %d\n\n", ret );
         goto exit;
     }
 
diff --git a/programs/ssl/ssl_mail_client.c b/programs/ssl/ssl_mail_client.c
index 4b5d177..665cdbf 100644
--- a/programs/ssl/ssl_mail_client.c
+++ b/programs/ssl/ssl_mail_client.c
@@ -532,11 +532,11 @@
 
 #if defined(POLARSSL_FS_IO)
     if( strlen( opt.key_file ) )
-        ret = x509parse_keyfile( &rsa, opt.key_file, "" );
+        ret = x509parse_keyfile_rsa( &rsa, opt.key_file, "" );
     else
 #endif
 #if defined(POLARSSL_CERTS_C)
-        ret = x509parse_key( &rsa, (const unsigned char *) test_cli_key,
+        ret = x509parse_key_rsa( &rsa, (const unsigned char *) test_cli_key,
                 strlen( test_cli_key ), NULL, 0 );
 #else
     {
@@ -546,7 +546,7 @@
 #endif
     if( ret != 0 )
     {
-        printf( " failed\n  !  x509parse_key returned %d\n\n", ret );
+        printf( " failed\n  !  x509parse_key_rsa returned %d\n\n", ret );
         goto exit;
     }
 
diff --git a/programs/ssl/ssl_server.c b/programs/ssl/ssl_server.c
index 3059236..dbb193b 100644
--- a/programs/ssl/ssl_server.c
+++ b/programs/ssl/ssl_server.c
@@ -117,7 +117,7 @@
     /*
      * This demonstration program uses embedded test certificates.
      * Instead, you may want to use x509parse_crtfile() to read the
-     * server and CA certificates, as well as x509parse_keyfile().
+     * server and CA certificates, as well as x509parse_keyfile_rsa().
      */
     ret = x509parse_crt( &srvcert, (const unsigned char *) test_srv_crt,
                          strlen( test_srv_crt ) );
@@ -136,11 +136,11 @@
     }
 
     rsa_init( &rsa, RSA_PKCS_V15, 0 );
-    ret =  x509parse_key( &rsa, (const unsigned char *) test_srv_key,
+    ret =  x509parse_key_rsa( &rsa, (const unsigned char *) test_srv_key,
                           strlen( test_srv_key ), NULL, 0 );
     if( ret != 0 )
     {
-        printf( " failed\n  !  x509parse_key returned %d\n\n", ret );
+        printf( " failed\n  !  x509parse_key_rsa returned %d\n\n", ret );
         goto exit;
     }
 
diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c
index 6197cda..db2d123 100644
--- a/programs/ssl/ssl_server2.c
+++ b/programs/ssl/ssl_server2.c
@@ -501,11 +501,11 @@
 
 #if defined(POLARSSL_FS_IO)
     if( strlen( opt.key_file ) )
-        ret = x509parse_keyfile( &rsa, opt.key_file, "" );
+        ret = x509parse_keyfile_rsa( &rsa, opt.key_file, "" );
     else
 #endif
 #if defined(POLARSSL_CERTS_C)
-        ret = x509parse_key( &rsa, (const unsigned char *) test_srv_key,
+        ret = x509parse_key_rsa( &rsa, (const unsigned char *) test_srv_key,
                 strlen( test_srv_key ), NULL, 0 );
 #else
     {
@@ -515,7 +515,7 @@
 #endif
     if( ret != 0 )
     {
-        printf( " failed\n  !  x509parse_key returned -0x%x\n\n", -ret );
+        printf( " failed\n  !  x509parse_key_rsa returned -0x%x\n\n", -ret );
         goto exit;
     }
 
diff --git a/programs/test/o_p_test.c b/programs/test/o_p_test.c
index 9726282..84dd38b 100644
--- a/programs/test/o_p_test.c
+++ b/programs/test/o_p_test.c
@@ -104,7 +104,7 @@
     fflush( stdout );
 
     rsa_init( &p_rsa, RSA_PKCS_V15, 0 );
-    if( x509parse_keyfile( &p_rsa, argv[1], NULL ) != 0 )
+    if( x509parse_keyfile_rsa( &p_rsa, argv[1], NULL ) != 0 )
     {
         ret = 1;
         printf( " failed\n  ! Could not load key.\n\n" );
diff --git a/programs/test/ssl_cert_test.c b/programs/test/ssl_cert_test.c
index 83a2a01..bf4684b 100644
--- a/programs/test/ssl_cert_test.c
+++ b/programs/test/ssl_cert_test.c
@@ -196,10 +196,10 @@
         printf( "  . Loading the client private key %s...", name );
         fflush( stdout );
 
-        ret = x509parse_keyfile( &rsa, name, NULL );
+        ret = x509parse_keyfile_rsa( &rsa, name, NULL );
         if( ret != 0 )
         {
-            printf( " failed\n  !  x509parse_key returned %d\n\n", ret );
+            printf( " failed\n  !  x509parse_key_rsa returned %d\n\n", ret );
             goto exit;
         }
 
diff --git a/programs/test/ssl_test.c b/programs/test/ssl_test.c
index 607b092..ce45ccf 100644
--- a/programs/test/ssl_test.c
+++ b/programs/test/ssl_test.c
@@ -229,11 +229,11 @@
             goto exit;
         }
 
-        ret =  x509parse_key( &rsa, (const unsigned char *) test_srv_key,
+        ret =  x509parse_key_rsa( &rsa, (const unsigned char *) test_srv_key,
                               strlen( test_srv_key ), NULL, 0 );
         if( ret != 0 )
         {
-            printf( "  !  x509parse_key returned %d\n\n", ret );
+            printf( "  !  x509parse_key_rsa returned %d\n\n", ret );
             goto exit;
         }
 #endif
diff --git a/programs/x509/cert_req.c b/programs/x509/cert_req.c
index 20418ab..cbd6252 100644
--- a/programs/x509/cert_req.c
+++ b/programs/x509/cert_req.c
@@ -267,14 +267,14 @@
     printf( "\n  . Loading the private key ..." );
     fflush( stdout );
 
-    ret = x509parse_keyfile( &rsa, opt.filename, NULL );
+    ret = x509parse_keyfile_rsa( &rsa, opt.filename, NULL );
 
     if( ret != 0 )
     {
 #ifdef POLARSSL_ERROR_C
         error_strerror( ret, buf, 1024 );
 #endif
-        printf( " failed\n  !  x509parse_key returned %d - %s\n\n", ret, buf );
+        printf( " failed\n  !  x509parse_key_rsa returned %d - %s\n\n", ret, buf );
         rsa_free( &rsa );
         goto exit;
     }
diff --git a/scripts/generate_errors.pl b/scripts/generate_errors.pl
index 009107b..7257ae6 100755
--- a/scripts/generate_errors.pl
+++ b/scripts/generate_errors.pl
@@ -13,7 +13,7 @@
                           "PADLOCK", "DES", "NET", "CTR_DRBG", "ENTROPY",
                           "MD2", "MD4", "MD5", "SHA1", "SHA256", "SHA512", "GCM" );
 my @high_level_modules = ( "PEM", "X509", "DHM", "RSA", "ECP", "MD", "CIPHER", "SSL",
-                           "PKCS12", "PKCS5" );
+                           "PK", "PKCS12", "PKCS5" );
 
 my $line_separator = $/;
 undef $/;
diff --git a/tests/data_files/ec_prv.pk8.der b/tests/data_files/ec_prv.pk8.der
new file mode 100644
index 0000000..f2bd2a9
--- /dev/null
+++ b/tests/data_files/ec_prv.pk8.der
Binary files differ
diff --git a/tests/data_files/ec_prv.pk8.pem b/tests/data_files/ec_prv.pk8.pem
new file mode 100644
index 0000000..dbeab7c
--- /dev/null
+++ b/tests/data_files/ec_prv.pk8.pem
@@ -0,0 +1,5 @@
+-----BEGIN PRIVATE KEY-----
+MG8CAQAwEwYHKoZIzj0CAQYIKoZIzj0DAQEEVTBTAgEBBBgzjoaogeI49Um9bwVT
+SUtz49YRMP3GyW2hNAMyAARRdbzfMKNw851Tk+YScojYAWe19LS3dsZ098bzVLfS
+JAYsH2hUtaevD+V46vJY8Cc=
+-----END PRIVATE KEY-----
diff --git a/tests/data_files/ec_prv.pk8.pw.der b/tests/data_files/ec_prv.pk8.pw.der
new file mode 100644
index 0000000..db0b5bd
--- /dev/null
+++ b/tests/data_files/ec_prv.pk8.pw.der
Binary files differ
diff --git a/tests/data_files/ec_prv.pk8.pw.pem b/tests/data_files/ec_prv.pk8.pw.pem
new file mode 100644
index 0000000..7413d1e
--- /dev/null
+++ b/tests/data_files/ec_prv.pk8.pw.pem
@@ -0,0 +1,6 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+MIGRMBwGCiqGSIb3DQEMAQEwDgQIIrlmCCSpJzcCAggABHGm2LyJ60ojfilRRp8h
+Xf+sWL3lJq6wlj4Nk41SHVnZ2RiVtP5NVK908/WxnXkridd6Qpjnq/14woWVmQxT
+IzhKFVi22YmQyBsNj+bEGDAE4c9qaby8u6zbzs7Qj29F90f/PiYsaIEGcNn/W88e
+XarNDw==
+-----END ENCRYPTED PRIVATE KEY-----
diff --git a/tests/data_files/ec_prv.sec1.der b/tests/data_files/ec_prv.sec1.der
new file mode 100644
index 0000000..fe336b7
--- /dev/null
+++ b/tests/data_files/ec_prv.sec1.der
Binary files differ
diff --git a/tests/data_files/ec_prv.sec1.pem b/tests/data_files/ec_prv.sec1.pem
new file mode 100644
index 0000000..a8a7990
--- /dev/null
+++ b/tests/data_files/ec_prv.sec1.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MF8CAQEEGDOOhqiB4jj1Sb1vBVNJS3Pj1hEw/cbJbaAKBggqhkjOPQMBAaE0AzIA
+BFF1vN8wo3DznVOT5hJyiNgBZ7X0tLd2xnT3xvNUt9IkBiwfaFS1p68P5Xjq8ljw
+Jw==
+-----END EC PRIVATE KEY-----
diff --git a/tests/data_files/ec_prv.sec1.pw.pem b/tests/data_files/ec_prv.sec1.pw.pem
new file mode 100644
index 0000000..62a0860
--- /dev/null
+++ b/tests/data_files/ec_prv.sec1.pw.pem
@@ -0,0 +1,8 @@
+-----BEGIN EC PRIVATE KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CBC,AA94892A169FA426
+
+gSkFuUENNke5MvkWHc11/w1NQWBxaIxGT+d5oRcqs44D3tltVOwtdnYexoD9uSIL
+wMFFRLL6I5ii1Naa38nPOMaa7kLU2J3jY8SeIH1rQ43X6tlpv9WFGqDn/m6X7oKo
+RMMfGdicPZg=
+-----END EC PRIVATE KEY-----
diff --git a/tests/data_files/ec_pub.der b/tests/data_files/ec_pub.der
new file mode 100644
index 0000000..74c5951
--- /dev/null
+++ b/tests/data_files/ec_pub.der
Binary files differ
diff --git a/tests/data_files/ec_pub.pem b/tests/data_files/ec_pub.pem
new file mode 100644
index 0000000..d677d27
--- /dev/null
+++ b/tests/data_files/ec_pub.pem
@@ -0,0 +1,4 @@
+-----BEGIN PUBLIC KEY-----
+MEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAEvHl9s65/COw9SWtPtBGz9iClWKUB
+4CItCM/g3Irsixp78kvpKVHMW6G+uyR0kJrg
+-----END PUBLIC KEY-----
diff --git a/tests/suites/test_suite_ecp.data b/tests/suites/test_suite_ecp.data
index 30fc461..73acb4f 100644
--- a/tests/suites/test_suite_ecp.data
+++ b/tests/suites/test_suite_ecp.data
@@ -245,6 +245,9 @@
 depends_on:POLARSSL_ECP_DP_SECP521R1_ENABLED
 ecp_tls_write_read_group:SECP521R1
 
+ECP check privkey
+ecp_check_privkey:SECP192R1
+
 ECP gen keypair
 depends_on:POLARSSL_ECP_DP_SECP192R1_ENABLED
 ecp_gen_keypair:SECP192R1
diff --git a/tests/suites/test_suite_ecp.function b/tests/suites/test_suite_ecp.function
index a051bd7..543175f 100644
--- a/tests/suites/test_suite_ecp.function
+++ b/tests/suites/test_suite_ecp.function
@@ -438,6 +438,28 @@
 END_CASE
 
 BEGIN_CASE
+ecp_check_privkey:id
+{
+    ecp_group grp;
+    mpi d;
+
+    ecp_group_init( &grp );
+    mpi_init( &d );
+
+    TEST_ASSERT( ecp_use_known_dp( &grp, POLARSSL_ECP_DP_{id} ) == 0 );
+
+    TEST_ASSERT( mpi_lset( &d, 0 ) == 0 );
+    TEST_ASSERT( ecp_check_privkey( &grp, &d ) == POLARSSL_ERR_ECP_GENERIC );
+
+    TEST_ASSERT( mpi_copy( &d, &grp.N ) == 0 );
+    TEST_ASSERT( ecp_check_privkey( &grp, &d ) == POLARSSL_ERR_ECP_GENERIC );
+
+    ecp_group_free( &grp );
+    mpi_free( &d );
+}
+END_CASE
+
+BEGIN_CASE
 ecp_gen_keypair:id
 {
     ecp_group grp;
@@ -455,8 +477,8 @@
     TEST_ASSERT( ecp_gen_keypair( &grp, &d, &Q, &rnd_pseudo_rand, &rnd_info )
                  == 0 );
 
-    TEST_ASSERT( mpi_cmp_mpi( &d, &grp.N ) < 0 );
-    TEST_ASSERT( mpi_cmp_int( &d, 1 ) >= 0 );
+    TEST_ASSERT( ecp_check_pubkey( &grp, &Q ) == 0 );
+    TEST_ASSERT( ecp_check_privkey( &grp, &d ) == 0 );
 
     ecp_group_free( &grp );
     ecp_point_free( &Q );
diff --git a/tests/suites/test_suite_x509parse.data b/tests/suites/test_suite_x509parse.data
index 570513b..def0021 100644
--- a/tests/suites/test_suite_x509parse.data
+++ b/tests/suites/test_suite_x509parse.data
@@ -78,113 +78,149 @@
 depends_on:POLARSSL_PEM_C:POLARSSL_FS_IO
 x509_crl_info:"data_files/crl_sha512.pem":"CRL version   \: 1\nissuer name   \: C=NL, O=PolarSSL, CN=PolarSSL Test CA\nthis update   \: 2011-02-12 14\:44\:07\nnext update   \: 2011-04-13 14\:44\:07\nRevoked certificates\:\nserial number\: 01 revocation date\: 2011-02-12 14\:44\:07\nserial number\: 03 revocation date\: 2011-02-12 14\:44\:07\nsigned using  \: RSA with SHA-512\n"
 
-X509 Parse Key #1 (No password when required)
+X509 Parse RSA Key #1 (No password when required)
 depends_on:POLARSSL_MD5_C:POLARSSL_PEM_C:POLARSSL_FS_IO
-x509parse_keyfile:"data_files/test-ca.key":NULL:POLARSSL_ERR_X509_PASSWORD_REQUIRED
+x509parse_keyfile_rsa:"data_files/test-ca.key":NULL:POLARSSL_ERR_X509_PASSWORD_REQUIRED
 
-X509 Parse Key #2 (Correct password)
+X509 Parse RSA Key #2 (Correct password)
 depends_on:POLARSSL_MD5_C:POLARSSL_PEM_C:POLARSSL_FS_IO
-x509parse_keyfile:"data_files/test-ca.key":"PolarSSLTest":0
+x509parse_keyfile_rsa:"data_files/test-ca.key":"PolarSSLTest":0
 
-X509 Parse Key #3 (Wrong password)
+X509 Parse RSA Key #3 (Wrong password)
 depends_on:POLARSSL_MD5_C:POLARSSL_PEM_C:POLARSSL_FS_IO
-x509parse_keyfile:"data_files/test-ca.key":"PolarSSLWRONG":POLARSSL_ERR_X509_PASSWORD_MISMATCH
+x509parse_keyfile_rsa:"data_files/test-ca.key":"PolarSSLWRONG":POLARSSL_ERR_X509_PASSWORD_MISMATCH
 
-X509 Parse Key #4 (DES Encrypted)
+X509 Parse RSA Key #4 (DES Encrypted)
 depends_on:POLARSSL_MD5_C:POLARSSL_DES_C:POLARSSL_PEM_C:POLARSSL_FS_IO
-x509parse_keyfile:"data_files/keyfile.des":"testkey":0
+x509parse_keyfile_rsa:"data_files/keyfile.des":"testkey":0
 
-X509 Parse Key #5 (3DES Encrypted)
+X509 Parse RSA Key #5 (3DES Encrypted)
 depends_on:POLARSSL_MD5_C:POLARSSL_DES_C:POLARSSL_PEM_C:POLARSSL_FS_IO
-x509parse_keyfile:"data_files/keyfile.3des":"testkey":0
+x509parse_keyfile_rsa:"data_files/keyfile.3des":"testkey":0
 
-X509 Parse Key #6 (AES-128 Encrypted)
+X509 Parse RSA Key #6 (AES-128 Encrypted)
 depends_on:POLARSSL_MD5_C:POLARSSL_AES_C:POLARSSL_PEM_C:POLARSSL_FS_IO
-x509parse_keyfile:"data_files/keyfile.aes128":"testkey":0
+x509parse_keyfile_rsa:"data_files/keyfile.aes128":"testkey":0
 
-X509 Parse Key #7 (AES-192 Encrypted)
+X509 Parse RSA Key #7 (AES-192 Encrypted)
 depends_on:POLARSSL_MD5_C:POLARSSL_AES_C:POLARSSL_PEM_C:POLARSSL_FS_IO
-x509parse_keyfile:"data_files/keyfile.aes192":"testkey":0
+x509parse_keyfile_rsa:"data_files/keyfile.aes192":"testkey":0
 
-X509 Parse Key #8 (AES-256 Encrypted)
+X509 Parse RSA Key #8 (AES-256 Encrypted)
 depends_on:POLARSSL_MD5_C:POLARSSL_AES_C:POLARSSL_PEM_C:POLARSSL_FS_IO
-x509parse_keyfile:"data_files/keyfile.aes256":"testkey":0
+x509parse_keyfile_rsa:"data_files/keyfile.aes256":"testkey":0
 
-X509 Parse Key #9 (PKCS#8 wrapped)
+X509 Parse RSA Key #9 (PKCS#8 wrapped)
 depends_on:POLARSSL_MD5_C:POLARSSL_PEM_C:POLARSSL_FS_IO
-x509parse_keyfile:"data_files/format_gen.key":"":0
+x509parse_keyfile_rsa:"data_files/format_gen.key":"":0
 
-X509 Parse Key #10 (PKCS#8 encrypted SHA1-3DES)
+X509 Parse RSA Key #10 (PKCS#8 encrypted SHA1-3DES)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_3des.key":"PolarSSLTest":0
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_3des.key":"PolarSSLTest":0
 
-X509 Parse Key #10.1 (PKCS#8 encrypted SHA1-3DES, wrong PW)
+X509 Parse RSA Key #10.1 (PKCS#8 encrypted SHA1-3DES, wrong PW)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_3des.key":"PolarSSLTes":POLARSSL_ERR_X509_PASSWORD_MISMATCH
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_3des.key":"PolarSSLTes":POLARSSL_ERR_X509_PASSWORD_MISMATCH
 
-X509 Parse Key #10.2 (PKCS#8 encrypted SHA1-3DES, no PW)
+X509 Parse RSA Key #10.2 (PKCS#8 encrypted SHA1-3DES, no PW)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_3des.key":"":POLARSSL_ERR_X509_PASSWORD_REQUIRED
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_3des.key":"":POLARSSL_ERR_X509_PASSWORD_REQUIRED
 
-X509 Parse Key #11 (PKCS#8 encrypted SHA1-3DES DER)
+X509 Parse RSA Key #11 (PKCS#8 encrypted SHA1-3DES DER)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_3des.der":"PolarSSLTest":0
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_3des.der":"PolarSSLTest":0
 
-X509 Parse Key #12 (PKCS#8 encrypted SHA1-2DES)
+X509 Parse RSA Key #12 (PKCS#8 encrypted SHA1-2DES)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_2des.key":"PolarSSLTest":0
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_2des.key":"PolarSSLTest":0
 
-X509 Parse Key #12.1 (PKCS#8 encrypted SHA1-2DES, wrong PW)
+X509 Parse RSA Key #12.1 (PKCS#8 encrypted SHA1-2DES, wrong PW)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_2des.key":"PolarSLTest":POLARSSL_ERR_X509_PASSWORD_MISMATCH
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_2des.key":"PolarSLTest":POLARSSL_ERR_X509_PASSWORD_MISMATCH
 
-X509 Parse Key #12.2 (PKCS#8 encrypted SHA1-2DES, no PW)
+X509 Parse RSA Key #12.2 (PKCS#8 encrypted SHA1-2DES, no PW)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_2des.key":"":POLARSSL_ERR_X509_PASSWORD_REQUIRED
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_2des.key":"":POLARSSL_ERR_X509_PASSWORD_REQUIRED
 
-X509 Parse Key #13 (PKCS#8 encrypted SHA1-RC4-128)
+X509 Parse RSA Key #13 (PKCS#8 encrypted SHA1-RC4-128)
 depends_on:POLARSSL_ARC4_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_rc4_128.key":"PolarSSLTest":0
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_rc4_128.key":"PolarSSLTest":0
 
-X509 Parse Key #13.1 (PKCS#8 encrypted SHA1-RC4-128, wrong PW)
+X509 Parse RSA Key #13.1 (PKCS#8 encrypted SHA1-RC4-128, wrong PW)
 depends_on:POLARSSL_ARC4_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_rc4_128.key":"PolarSSLTe":POLARSSL_ERR_X509_PASSWORD_MISMATCH
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_rc4_128.key":"PolarSSLTe":POLARSSL_ERR_X509_PASSWORD_MISMATCH
 
-X509 Parse Key #13.2 (PKCS#8 encrypted SHA1-RC4-128, no PW)
+X509 Parse RSA Key #13.2 (PKCS#8 encrypted SHA1-RC4-128, no PW)
 depends_on:POLARSSL_ARC4_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS12_C
-x509parse_keyfile:"data_files/pkcs8_pbe_sha1_rc4_128.key":"":POLARSSL_ERR_X509_PASSWORD_REQUIRED
+x509parse_keyfile_rsa:"data_files/pkcs8_pbe_sha1_rc4_128.key":"":POLARSSL_ERR_X509_PASSWORD_REQUIRED
 
-X509 Parse Key #14 (PKCS#8 encrypted v2 PBDFK2 3DES)
+X509 Parse RSA Key #14 (PKCS#8 encrypted v2 PBDFK2 3DES)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS5_C
-x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.key":"PolarSSLTest":0
+x509parse_keyfile_rsa:"data_files/pkcs8_pbes2_pbkdf2_3des.key":"PolarSSLTest":0
 
-X509 Parse Key #15 (PKCS#8 encrypted v2 PBDFK2 3DES, wrong PW)
+X509 Parse RSA Key #15 (PKCS#8 encrypted v2 PBDFK2 3DES, wrong PW)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS5_C
-x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.key":"PolarSSLTes":POLARSSL_ERR_X509_PASSWORD_MISMATCH
+x509parse_keyfile_rsa:"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)
+X509 Parse RSA Key #16 (PKCS#8 encrypted v2 PBDFK2 3DES, no PW)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS5_C
-x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.key":"":POLARSSL_ERR_X509_PASSWORD_REQUIRED
+x509parse_keyfile_rsa:"data_files/pkcs8_pbes2_pbkdf2_3des.key":"":POLARSSL_ERR_X509_PASSWORD_REQUIRED
 
-X509 Parse Key #17 (PKCS#8 encrypted v2 PBDFK2 3DES DER)
+X509 Parse RSA Key #17 (PKCS#8 encrypted v2 PBDFK2 3DES DER)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_FS_IO:POLARSSL_PKCS5_C
-x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.der":"PolarSSLTest":0
+x509parse_keyfile_rsa:"data_files/pkcs8_pbes2_pbkdf2_3des.der":"PolarSSLTest":0
 
-X509 Parse Key #18 (PKCS#8 encrypted v2 PBDFK2 3DES DER, wrong PW)
+X509 Parse RSA Key #18 (PKCS#8 encrypted v2 PBDFK2 3DES DER, wrong PW)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_FS_IO:POLARSSL_PKCS5_C
-x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.der":"PolarSSLTes":POLARSSL_ERR_X509_PASSWORD_MISMATCH
+x509parse_keyfile_rsa:"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)
+X509 Parse RSA Key #19 (PKCS#8 encrypted v2 PBDFK2 3DES DER, no PW)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_FS_IO:POLARSSL_PKCS5_C
-x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_3des.der":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
+x509parse_keyfile_rsa:"data_files/pkcs8_pbes2_pbkdf2_3des.der":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
 
-X509 Parse Key #20 (PKCS#8 encrypted v2 PBDFK2 DES)
+X509 Parse RSA Key #20 (PKCS#8 encrypted v2 PBDFK2 DES)
 depends_on:POLARSSL_DES_C:POLARSSL_SHA1_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_PKCS5_C
-x509parse_keyfile:"data_files/pkcs8_pbes2_pbkdf2_des.key":"PolarSSLTest":0
+x509parse_keyfile_rsa:"data_files/pkcs8_pbes2_pbkdf2_des.key":"PolarSSLTest":0
 
-X509 Parse Public Key #1 (PKCS#8 wrapped)
+X509 Parse Public RSA 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
+x509parse_public_keyfile_rsa:"data_files/format_gen.pub":0
+
+X509 Parse Public EC Key #1 (RFC 5480, DER)
+depends_on:POLARSSL_ECP_C:POLARSSL_FS_IO
+x509parse_public_keyfile_ec:"data_files/ec_pub.der":0
+
+X509 Parse Public EC Key #2 (RFC 5480, PEM)
+depends_on:POLARSSL_PEM_C:POLARSSL_ECP_C:POLARSSL_FS_IO
+x509parse_public_keyfile_ec:"data_files/ec_pub.pem":0
+
+X509 Parse EC Key #1 (SEC1 DER)
+depends_on:POLARSSL_FS_IO:POLARSSL_ECP_C
+x509parse_keyfile_ec:"data_files/ec_prv.sec1.der":NULL:0
+
+X509 Parse EC Key #2 (SEC1 PEM)
+depends_on:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_ECP_C
+x509parse_keyfile_ec:"data_files/ec_prv.sec1.pem":NULL:0
+
+X509 Parse EC Key #3 (SEC1 PEM encrypted)
+depends_on:POLARSSL_DES_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_ECP_C
+x509parse_keyfile_ec:"data_files/ec_prv.sec1.pw.pem":"polar":0
+
+X509 Parse EC Key #4 (PKCS8 DER)
+depends_on:POLARSSL_FS_IO:POLARSSL_ECP_C
+x509parse_keyfile_ec:"data_files/ec_prv.pk8.der":NULL:0
+
+X509 Parse EC Key #5 (PKCS8 PEM)
+depends_on:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_ECP_C
+x509parse_keyfile_ec:"data_files/ec_prv.pk8.pem":NULL:0
+
+X509 Parse EC Key #6 (PKCS8 encrypted DER)
+depends_on:POLARSSL_DES_C:POLARSSL_FS_IO:POLARSSL_ECP_C
+x509parse_keyfile_ec:"data_files/ec_prv.pk8.pw.der":"polar":0
+
+X509 Parse EC Key #7 (PKCS8 encrypted PEM)
+depends_on:POLARSSL_DES_C:POLARSSL_PEM_C:POLARSSL_FS_IO:POLARSSL_ECP_C
+x509parse_keyfile_ec:"data_files/ec_prv.pk8.pw.pem":"polar":0
 
 X509 Get Distinguished Name #1
 depends_on:POLARSSL_PEM_C:POLARSSL_FS_IO
@@ -652,22 +688,22 @@
 x509parse_crl:"30463031020100300d06092a864886f70d01010e0500300f310d300b0603550403130441424344170c303930313031303030303030300d06092a864886f70d01010e050003020001":"CRL version   \: 1\nissuer name   \: CN=ABCD\nthis update   \: 2009-01-01 00\:00\:00\nnext update   \: 0000-00-00 00\:00\:00\nRevoked certificates\:\nsigned using  \: RSA with SHA-224\n":0
 
 X509 Key ASN1 (Incorrect first tag)
-x509parse_key:"":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
+x509parse_key_rsa:"":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
 
 X509 Key ASN1 (RSAPrivateKey, incorrect version tag)
-x509parse_key:"300100":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
+x509parse_key_rsa:"300100":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
 
 X509 Key ASN1 (RSAPrivateKey, version tag missing)
-x509parse_key:"3000":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
+x509parse_key_rsa:"3000":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
 
 X509 Key ASN1 (RSAPrivateKey, invalid version)
-x509parse_key:"3003020101":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
+x509parse_key_rsa:"3003020101":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
 
 X509 Key ASN1 (RSAPrivateKey, correct version, incorrect tag)
-x509parse_key:"300402010000":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
+x509parse_key_rsa:"300402010000":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
 
 X509 Key ASN1 (RSAPrivateKey, values present, length mismatch)
-x509parse_key:"301c02010002010102010102010102010102010102010102010102010100":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
+x509parse_key_rsa:"301c02010002010102010102010102010102010102010102010102010100":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
 
 X509 Key ASN1 (RSAPrivateKey, values present, check_privkey fails)
-x509parse_key:"301b020100020101020101020101020101020101020101020101020101":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
+x509parse_key_rsa:"301b020100020101020101020101020101020101020101020101020101":"":POLARSSL_ERR_X509_KEY_INVALID_FORMAT
diff --git a/tests/suites/test_suite_x509parse.function b/tests/suites/test_suite_x509parse.function
index 8b69327..b6383d7 100644
--- a/tests/suites/test_suite_x509parse.function
+++ b/tests/suites/test_suite_x509parse.function
@@ -138,14 +138,14 @@
 END_CASE
 
 BEGIN_CASE
-x509parse_keyfile:key_file:password:result
+x509parse_keyfile_rsa:key_file:password:result
 {
     rsa_context rsa;
     int res;
 
     memset( &rsa, 0, sizeof( rsa_context ) );
 
-    res = x509parse_keyfile( &rsa, {key_file}, {password} );
+    res = x509parse_keyfile_rsa( &rsa, {key_file}, {password} );
 
     TEST_ASSERT( res == {result} );
 
@@ -159,14 +159,14 @@
 END_CASE
 
 BEGIN_CASE
-x509parse_public_keyfile:key_file:result
+x509parse_public_keyfile_rsa:key_file:result
 {
     rsa_context rsa;
     int res;
 
     memset( &rsa, 0, sizeof( rsa_context ) );
 
-    res = x509parse_public_keyfile( &rsa, {key_file} );
+    res = x509parse_public_keyfile_rsa( &rsa, {key_file} );
 
     TEST_ASSERT( res == {result} );
 
@@ -180,6 +180,54 @@
 END_CASE
 
 BEGIN_CASE
+x509parse_public_keyfile_ec:key_file:result
+{
+    pk_context ctx;
+    int res;
+
+    pk_init( &ctx );
+
+    res = x509parse_public_keyfile( &ctx, {key_file} );
+
+    TEST_ASSERT( res == {result} );
+
+    if( res == 0 )
+    {
+        ecp_keypair *eckey;
+        TEST_ASSERT( ctx.type == POLARSSL_PK_ECKEY );
+        eckey = (ecp_keypair *) ctx.data;
+        TEST_ASSERT( ecp_check_pubkey( &eckey->grp, &eckey->Q ) == 0 );
+    }
+
+    pk_free( &ctx );
+}
+END_CASE
+
+BEGIN_CASE
+x509parse_keyfile_ec:key_file:password:result
+{
+    pk_context ctx;
+    int res;
+
+    pk_init( &ctx );
+
+    res = x509parse_keyfile( &ctx, {key_file}, {password} );
+
+    TEST_ASSERT( res == {result} );
+
+    if( res == 0 )
+    {
+        ecp_keypair *eckey;
+        TEST_ASSERT( ctx.type == POLARSSL_PK_ECKEY );
+        eckey = (ecp_keypair *) ctx.data;
+        TEST_ASSERT( ecp_check_privkey( &eckey->grp, &eckey->d ) == 0 );
+    }
+
+    pk_free( &ctx );
+}
+END_CASE
+
+BEGIN_CASE
 x509parse_crt:crt_data:result_str:result
 {
     x509_cert   crt;
@@ -238,7 +286,7 @@
 END_CASE
 
 BEGIN_CASE
-x509parse_key:key_data:result_str:result
+x509parse_key_rsa:key_data:result_str:result
 {
     rsa_context   rsa;
     unsigned char buf[2000];
@@ -251,7 +299,7 @@
 
     data_len = unhexify( buf, {key_data} );
 
-    TEST_ASSERT( x509parse_key( &rsa, buf, data_len, NULL, 0 ) == ( {result} ) );
+    TEST_ASSERT( x509parse_key_rsa( &rsa, buf, data_len, NULL, 0 ) == ( {result} ) );
     if( ( {result} ) == 0 )
     {
         TEST_ASSERT( 1 );
diff --git a/tests/suites/test_suite_x509write.function b/tests/suites/test_suite_x509write.function
index 8ce3e71..e3bf12f 100644
--- a/tests/suites/test_suite_x509write.function
+++ b/tests/suites/test_suite_x509write.function
@@ -41,7 +41,7 @@
     strcpy( cur->name, "NL" );
 
     memset( &rsa, 0, sizeof(rsa_context) );
-    ret = x509parse_keyfile( &rsa, {key_file}, NULL );
+    ret = x509parse_keyfile_rsa( &rsa, {key_file}, NULL );
     TEST_ASSERT( ret == 0 );
     if( ret != 0 )
         return 0;