浏览代码

re-factor PKCS#8 API a bit

Signed-off-by: Steffen Jaeckel <[email protected]>
Steffen Jaeckel 3 年之前
父节点
当前提交
3f6f885852

+ 0 - 4
src/headers/tomcrypt_misc.h

@@ -160,10 +160,6 @@ int padding_depad(const unsigned char *data, unsigned long *length, unsigned lon
 #endif  /* LTC_PADDING */
 
 #ifdef LTC_PEM
-typedef struct {
-   int (*callback)(void **, unsigned long *, void *);
-   void *userdata;
-} password_ctx;
 
 #ifdef LTC_SSH
 int pem_decode_openssh_filehandle(FILE *f, ltc_pka_key *k, password_ctx *pw_ctx);

+ 13 - 8
src/headers/tomcrypt_pk.h

@@ -1,6 +1,11 @@
 /* LibTomCrypt, modular cryptographic library -- Tom St Denis */
 /* SPDX-License-Identifier: Unlicense */
 
+typedef struct {
+   int (*callback)(void **, unsigned long *, void *);
+   void *userdata;
+} password_ctx;
+
 /* ---- NUMBER THEORY ---- */
 
 enum public_key_type {
@@ -108,7 +113,7 @@ int rsa_import(const unsigned char *in, unsigned long inlen, rsa_key *key);
 
 int rsa_import_x509(const unsigned char *in, unsigned long inlen, rsa_key *key);
 int rsa_import_pkcs8(const unsigned char *in, unsigned long inlen,
-                     const void *passwd, unsigned long passwdlen, rsa_key *key);
+                     const password_ctx  *pw_ctx, rsa_key *key);
 
 int rsa_set_key(const unsigned char *N,  unsigned long Nlen,
                 const unsigned char *e,  unsigned long elen,
@@ -280,7 +285,7 @@ int ecc_ansi_x963_import_ex(const unsigned char *in, unsigned long inlen, ecc_ke
 
 int ecc_export_openssl(unsigned char *out, unsigned long *outlen, int type, const ecc_key *key);
 int ecc_import_openssl(const unsigned char *in, unsigned long inlen, ecc_key *key);
-int ecc_import_pkcs8(const unsigned char *in, unsigned long inlen, const void *pwd, unsigned long pwdlen, ecc_key *key);
+int ecc_import_pkcs8(const unsigned char *in, unsigned long inlen, const password_ctx *pw_ctx, ecc_key *key);
 int ecc_import_x509(const unsigned char *in, unsigned long inlen, ecc_key *key);
 
 int  ecc_shared_secret(const ecc_key *private_key, const ecc_key *public_key,
@@ -353,9 +358,9 @@ int ed25519_export(       unsigned char *out, unsigned long *outlen,
 int ed25519_import(const unsigned char *in, unsigned long inlen, curve25519_key *key);
 int ed25519_import_raw(const unsigned char *in, unsigned long inlen, int which, curve25519_key *key);
 int ed25519_import_x509(const unsigned char *in, unsigned long inlen, curve25519_key *key);
-int ed25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
-                                  const void *pwd, unsigned long pwdlen,
-                              curve25519_key *key);
+int ed25519_import_pkcs8(const unsigned char  *in, unsigned long inlen,
+                         const password_ctx   *pw_ctx,
+                               curve25519_key *key);
 
 int ed25519_sign(const  unsigned char *msg, unsigned long msglen,
                         unsigned char *sig, unsigned long *siglen,
@@ -393,9 +398,9 @@ int x25519_export(       unsigned char *out, unsigned long *outlen,
 int x25519_import(const unsigned char *in, unsigned long inlen, curve25519_key *key);
 int x25519_import_raw(const unsigned char *in, unsigned long inlen, int which, curve25519_key *key);
 int x25519_import_x509(const unsigned char *in, unsigned long inlen, curve25519_key *key);
-int x25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
-                                 const void *pwd, unsigned long pwdlen,
-                             curve25519_key *key);
+int x25519_import_pkcs8(const unsigned char  *in, unsigned long inlen,
+                        const password_ctx   *pw_ctx,
+                              curve25519_key *key);
 
 int x25519_shared_secret(const curve25519_key *private_key,
                          const curve25519_key *public_key,

+ 39 - 8
src/headers/tomcrypt_private.h

@@ -84,7 +84,7 @@ typedef struct {
 typedef struct
 {
    pbes_properties type;
-   const void *pwd;
+   void *pwd;
    unsigned long pwdlen;
    ltc_asn1_list *enc_data;
    ltc_asn1_list *salt;
@@ -343,6 +343,7 @@ int ecc_set_curve_from_mpis(void *a, void *b, void *prime, void *order, void *gx
 int ecc_copy_curve(const ecc_key *srckey, ecc_key *key);
 int ecc_set_curve_by_size(int size, ecc_key *key);
 int ecc_import_subject_public_key_info(const unsigned char *in, unsigned long inlen, ecc_key *key);
+int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_key *key);
 
 #ifdef LTC_SSH
 int ecc_ssh_ecdsa_encode_name(char *buffer, unsigned long *buflen, const ecc_key *key);
@@ -435,11 +436,18 @@ int tweetnacl_crypto_scalarmult(unsigned char *q, const unsigned char *n, const
 int tweetnacl_crypto_scalarmult_base(unsigned char *q,const unsigned char *n);
 int tweetnacl_crypto_ph(unsigned char *out, const unsigned char *msg, unsigned long long msglen);
 
-typedef int (*sk_to_pk)(unsigned char *pk ,const unsigned char *sk);
+int ed25519_import_pkcs8_asn1(ltc_asn1_list  *alg_id, ltc_asn1_list *priv_key,
+                              curve25519_key *key);
+int x25519_import_pkcs8_asn1(ltc_asn1_list  *alg_id, ltc_asn1_list *priv_key,
+                             curve25519_key *key);
+
+int ec25519_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
+                              enum ltc_oid_id id,
+                              curve25519_key *key);
 int ec25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
-                       const void *pwd, unsigned long pwdlen,
-                       enum ltc_oid_id id, sk_to_pk fp,
-                       curve25519_key *key);
+                         const password_ctx  *pw_ctx,
+                         enum ltc_oid_id id,
+                         curve25519_key *key);
 int ec25519_export(       unsigned char *out, unsigned long *outlen,
                                     int  which,
                    const curve25519_key *key);
@@ -522,12 +530,35 @@ int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2);
 
 #ifdef LTC_PKCS_8
 
+/* Public-Key Cryptography Standards (PKCS) #8:
+ * Private-Key Information Syntax Specification Version 1.2
+ * https://tools.ietf.org/html/rfc5208
+ *
+ * PrivateKeyInfo ::= SEQUENCE {
+ *      version                   Version,
+ *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
+ *      privateKey                PrivateKey,
+ *      attributes           [0]  IMPLICIT Attributes OPTIONAL }
+ * where:
+ * - Version ::= INTEGER
+ * - PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
+ * - PrivateKey ::= OCTET STRING
+ * - Attributes ::= SET OF Attribute
+ *
+ * EncryptedPrivateKeyInfo ::= SEQUENCE {
+ *        encryptionAlgorithm  EncryptionAlgorithmIdentifier,
+ *        encryptedData        EncryptedData }
+ * where:
+ * - EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
+ * - EncryptedData ::= OCTET STRING
+ */
+
 int pkcs8_decode_flexi(const unsigned char  *in,  unsigned long inlen,
-                                    const void  *pwd, unsigned long pwdlen,
-                                 ltc_asn1_list **decoded_list);
+                       const password_ctx   *pw_ctx,
+                             ltc_asn1_list **decoded_list);
 
 int pkcs8_get_children(const ltc_asn1_list *decoded_list, enum ltc_oid_id *pka,
-                        ltc_asn1_list **seq, ltc_asn1_list **priv_key);
+                        ltc_asn1_list **alg_id, ltc_asn1_list **priv_key);
 
 #endif  /* LTC_PKCS_8 */
 

+ 15 - 5
src/pk/asn1/pkcs8/pkcs8_decode_flexi.c

@@ -15,7 +15,7 @@
    @return CRYPT_OK on success
 */
 int pkcs8_decode_flexi(const unsigned char  *in,  unsigned long inlen,
-                                const void  *pwd, unsigned long pwdlen,
+                       const password_ctx   *pw_ctx,
                              ltc_asn1_list **decoded_list)
 {
    unsigned long len = inlen;
@@ -23,10 +23,13 @@ int pkcs8_decode_flexi(const unsigned char  *in,  unsigned long inlen,
    unsigned char *dec_data = NULL;
    ltc_asn1_list *l = NULL;
    int err;
+   pbes_arg pbes;
 
    LTC_ARGCHK(in           != NULL);
    LTC_ARGCHK(decoded_list != NULL);
 
+   XMEMSET(&pbes, 0, sizeof(pbes));
+
    *decoded_list = NULL;
    if ((err = der_decode_sequence_flexi(in, &len, &l)) == CRYPT_OK) {
       /* the following "if" detects whether it is encrypted or not */
@@ -44,9 +47,9 @@ int pkcs8_decode_flexi(const unsigned char  *in,  unsigned long inlen,
           LTC_ASN1_IS_TYPE(l->child->child->next, LTC_ASN1_SEQUENCE) &&
           LTC_ASN1_IS_TYPE(l->child->next, LTC_ASN1_OCTET_STRING)) {
          ltc_asn1_list *lalgoid = l->child->child;
-         pbes_arg pbes;
 
-         XMEMSET(&pbes, 0, sizeof(pbes));
+         LTC_ARGCHK(pw_ctx           != NULL);
+         LTC_ARGCHK(pw_ctx->callback != NULL);
 
          if (pbes1_extract(lalgoid, &pbes) == CRYPT_OK) {
             /* Successfully extracted PBES1 parameters */
@@ -58,9 +61,12 @@ int pkcs8_decode_flexi(const unsigned char  *in,  unsigned long inlen,
             goto LBL_DONE;
          }
 
+         if (pw_ctx->callback(&pbes.pwd, &pbes.pwdlen, pw_ctx->userdata)) {
+            err = CRYPT_ERROR;
+            goto LBL_DONE;
+         }
+
          pbes.enc_data = l->child->next;
-         pbes.pwd = pwd;
-         pbes.pwdlen = pwdlen;
 
          dec_size = pbes.enc_data->size;
          if ((dec_data = XMALLOC(dec_size)) == NULL) {
@@ -87,6 +93,10 @@ int pkcs8_decode_flexi(const unsigned char  *in,  unsigned long inlen,
 
 LBL_DONE:
    if (l) der_free_sequence_flexi(l);
+   if (pbes.pwd) {
+      zeromem(pbes.pwd, pbes.pwdlen);
+      XFREE(pbes.pwd);
+   }
    if (dec_data) {
       zeromem(dec_data, dec_size);
       XFREE(dec_data);

+ 59 - 60
src/pk/ec25519/ec25519_import_pkcs8.c

@@ -9,78 +9,77 @@
 
 #ifdef LTC_CURVE25519
 
+typedef int (*sk_to_pk)(unsigned char *pk , const unsigned char *sk);
+
+int ec25519_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key,
+                              enum ltc_oid_id id,
+                              curve25519_key *key)
+{
+   int err;
+   unsigned long key_len;
+   sk_to_pk fp;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   LTC_UNUSED_PARAM(alg_id);
+
+   switch (id) {
+      case LTC_OID_ED25519:
+         fp = tweetnacl_crypto_sk_to_pk;
+         break;
+      case LTC_OID_X25519:
+         fp = tweetnacl_crypto_scalarmult_base;
+         break;
+      default:
+         return CRYPT_PK_INVALID_TYPE;
+   }
+
+   key_len = sizeof(key->priv);
+   if ((err = der_decode_octet_string(priv_key->data, priv_key->size, key->priv, &key_len)) == CRYPT_OK) {
+      fp(key->pub, key->priv);
+      key->type = PK_PRIVATE;
+      key->algo = id;
+   }
+   return err;
+}
+
 /**
   Generic import of a Curve/Ed25519 private key in PKCS#8 format
-  @param in        The DER-encoded PKCS#8-formatted private key
-  @param inlen     The length of the input data
-  @param passwd    The password to decrypt the private key
-  @param passwdlen Password's length (octets)
-  @param key       [out] Where to import the key to
+  @param in        The packet to import from
+  @param inlen     It's length (octets)
+  @param pw_ctx    The password context when decrypting the private key
+  @param id        The type of the private key
+  @param key       [out] Destination for newly imported key
   @return CRYPT_OK if successful, on error all allocated memory is freed automatically
 */
 int ec25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
-                       const void *pwd, unsigned long pwdlen,
-                       enum ltc_oid_id id, sk_to_pk fp,
-                       curve25519_key *key)
+                         const password_ctx   *pw_ctx,
+                         enum ltc_oid_id id,
+                         curve25519_key *key)
 {
-   int err;
+   int           err;
    ltc_asn1_list *l = NULL;
-   const char *oid;
-   ltc_asn1_list alg_id[1];
-   unsigned char private_key[34];
-   unsigned long version, key_len;
-   unsigned long tmpoid[16];
-
-   LTC_ARGCHK(in  != NULL);
-   LTC_ARGCHK(key != NULL);
-   LTC_ARGCHK(fp != NULL);
-
-   if ((err = pkcs8_decode_flexi(in, inlen, pwd, pwdlen, &l)) == CRYPT_OK) {
+   ltc_asn1_list *alg_id, *priv_key;
+   enum ltc_oid_id pka;
 
-      LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid) / sizeof(tmpoid[0]));
+   LTC_ARGCHK(in != NULL);
 
-      key_len = sizeof(private_key);
-      if ((err = der_decode_sequence_multi(l->data, l->size,
-                                           LTC_ASN1_SHORT_INTEGER,      1uL, &version,
-                                           LTC_ASN1_SEQUENCE,           1uL, alg_id,
-                                           LTC_ASN1_OCTET_STRING,   key_len, private_key,
-                                           LTC_ASN1_EOL,                0uL, NULL))
-          != CRYPT_OK) {
-         /* If there are attributes added after the private_key it is tagged with version 1 and
-          * we get an 'input too long' error but the rest is already decoded and can be
-          * handled the same as for version 0
-          */
-         if ((err == CRYPT_INPUT_TOO_LONG) && (version == 1)) {
-            version = 0;
-         } else {
-            goto out;
-         }
-      }
+   err = pkcs8_decode_flexi(in, inlen, pw_ctx, &l);
+   if (err != CRYPT_OK) return err;
 
-      if ((err = pk_get_oid(id, &oid)) != CRYPT_OK) {
-         goto out;
-      }
-      if ((err = pk_oid_cmp_with_asn1(oid, &alg_id[0])) != CRYPT_OK) {
-         goto out;
-      }
-
-      if (version == 0) {
-         key_len = sizeof(key->priv);
-         if ((err = der_decode_octet_string(private_key, sizeof(private_key), key->priv, &key_len)) == CRYPT_OK) {
-            fp(key->pub, key->priv);
-            key->type = PK_PRIVATE;
-            key->algo = id;
-         }
-      } else {
-         err = CRYPT_PK_INVALID_TYPE;
-      }
+   if ((err = pkcs8_get_children(l, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
+      goto LBL_DER_FREE;
    }
-out:
-   if (l) der_free_sequence_flexi(l);
-#ifdef LTC_CLEAN_STACK
-   zeromem(private_key, sizeof(private_key));
-#endif
+   if (pka != id) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_DER_FREE;
+   }
+
+   err = ec25519_import_pkcs8_asn1(alg_id, priv_key, id, key);
 
+LBL_DER_FREE:
+   der_free_sequence_flexi(l);
    return err;
 }
 

+ 126 - 115
src/pk/ecc/ecc_import_pkcs8.c

@@ -5,140 +5,113 @@
 
 #ifdef LTC_MECC
 
-/* NOTE: s_der_decode_pkcs8_flexi & related stuff can be shared with rsa_import_pkcs8() */
-
-int ecc_import_pkcs8(const unsigned char *in, unsigned long inlen,
-                     const void *pwd, unsigned long pwdlen,
-                     ecc_key *key)
+int ecc_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, ecc_key *key)
 {
    void          *a, *b, *gx, *gy;
    unsigned long len, cofactor, n;
-   const char    *pka_ec_oid;
    int           err;
    char          OID[256];
    const ltc_ecc_curve *curve;
-   ltc_asn1_list *p = NULL, *l = NULL;
-   der_flexi_check flexi_should[7];
-   ltc_asn1_list *seq, *priv_key;
+   ltc_asn1_list *p = NULL;
+   der_flexi_check case2_should[7];
+   ltc_asn1_list *version, *field, *point, *point_g, *order, *p_cofactor;
 
-   LTC_ARGCHK(in          != NULL);
    LTC_ARGCHK(key         != NULL);
    LTC_ARGCHK(ltc_mp.name != NULL);
 
-   /* get EC alg oid */
-   err = pk_get_oid(LTC_OID_EC, &pka_ec_oid);
-   if (err != CRYPT_OK) return err;
-
    /* init key */
    err = mp_init_multi(&a, &b, &gx, &gy, LTC_NULL);
-   if (err != CRYPT_OK) return err;
+   if (err != CRYPT_OK) goto LBL_DER_FREE;
+
+   /* Setup for CASE 2 */
+   n=0;
+   LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_INTEGER, &version);
+   LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_SEQUENCE, &field);
+   LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_SEQUENCE, &point);
+   LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_OCTET_STRING, &point_g);
+   LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_INTEGER, &order);
+   LTC_SET_DER_FLEXI_CHECK(case2_should, n++, LTC_ASN1_INTEGER, &p_cofactor);
+   LTC_SET_DER_FLEXI_CHECK(case2_should, n, LTC_ASN1_EOL, NULL);
+
+   if (LTC_ASN1_IS_TYPE(alg_id->child->next, LTC_ASN1_OBJECT_IDENTIFIER)) {
+      /* CASE 1: curve by OID (AKA short variant):
+       *   0:d=0  hl=2 l= 100 cons: SEQUENCE
+       *   2:d=1  hl=2 l=   1 prim:   INTEGER        :00
+       *   5:d=1  hl=2 l=  16 cons:   SEQUENCE       (== *seq)
+       *   7:d=2  hl=2 l=   7 prim:     OBJECT       :id-ecPublicKey
+       *  16:d=2  hl=2 l=   5 prim:     OBJECT       :(== *curve_oid (e.g. secp256k1 (== 1.3.132.0.10)))
+       *  23:d=1  hl=2 l=  77 prim:   OCTET STRING   :bytes (== *priv_key)
+       */
+      ltc_asn1_list *curve_oid = alg_id->child->next;
+      len = sizeof(OID);
+      if ((err = pk_oid_num_to_str(curve_oid->data, curve_oid->size, OID, &len)) != CRYPT_OK) { goto LBL_DONE; }
+      if ((err = ecc_find_curve(OID, &curve)) != CRYPT_OK)                          { goto LBL_DONE; }
+      if ((err = ecc_set_curve(curve, key)) != CRYPT_OK)                            { goto LBL_DONE; }
+   } else if (der_flexi_sequence_cmp(alg_id->child->next, case2_should) == CRYPT_OK) {
+
+      /* CASE 2: explicit curve parameters (AKA long variant):
+       *   0:d=0  hl=3 l= 227 cons: SEQUENCE
+       *   3:d=1  hl=2 l=   1 prim:   INTEGER              :00
+       *   6:d=1  hl=3 l= 142 cons:   SEQUENCE             (== *seq)
+       *   9:d=2  hl=2 l=   7 prim:     OBJECT             :id-ecPublicKey
+       *  18:d=2  hl=3 l= 130 cons:     SEQUENCE
+       *  21:d=3  hl=2 l=   1 prim:       INTEGER          :01
+       *  24:d=3  hl=2 l=  44 cons:       SEQUENCE         (== *field)
+       *  26:d=4  hl=2 l=   7 prim:         OBJECT         :prime-field
+       *  35:d=4  hl=2 l=  33 prim:         INTEGER        :(== *prime / curve.prime)
+       *  70:d=3  hl=2 l=   6 cons:       SEQUENCE         (== *point)
+       *  72:d=4  hl=2 l=   1 prim:         OCTET STRING   :bytes (== curve.A)
+       *  75:d=4  hl=2 l=   1 prim:         OCTET STRING   :bytes (== curve.B)
+       *  78:d=3  hl=2 l=  33 prim:       OCTET STRING     :bytes (== *g_point / curve.G-point)
+       * 113:d=3  hl=2 l=  33 prim:       INTEGER          :(== *order / curve.order)
+       * 148:d=3  hl=2 l=   1 prim:       INTEGER          :(== curve.cofactor)
+       * 151:d=1  hl=2 l=  77 prim:   OCTET STRING         :bytes (== *priv_key)
+       */
+
+      if (mp_cmp_d(version->data, 1) != LTC_MP_EQ) {
+         goto LBL_DONE;
+      }
+      cofactor = mp_get_int(p_cofactor->data);
 
+      if (LTC_ASN1_IS_TYPE(field->child, LTC_ASN1_OBJECT_IDENTIFIER) &&
+          LTC_ASN1_IS_TYPE(field->child->next, LTC_ASN1_INTEGER) &&
+          LTC_ASN1_IS_TYPE(point->child, LTC_ASN1_OCTET_STRING) &&
+          LTC_ASN1_IS_TYPE(point->child->next, LTC_ASN1_OCTET_STRING)) {
 
-   if (pkcs8_decode_flexi(in, inlen, pwd, pwdlen, &l) == CRYPT_OK) {
-
-      /* Setup for basic structure */
-      n=0;
-      LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, NULL);
-      LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seq);
-      LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &priv_key);
-      LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
-
-      if ((der_flexi_sequence_cmp(l, flexi_should) == CRYPT_OK) &&
-            (pk_oid_cmp_with_asn1(pka_ec_oid, seq->child) == CRYPT_OK)) {
-         ltc_asn1_list *version, *field, *point, *point_g, *order, *p_cofactor;
-
-         /* Setup for CASE 2 */
-         n=0;
-         LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &version);
-         LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &field);
-         LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &point);
-         LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OCTET_STRING, &point_g);
-         LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &order);
-         LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_INTEGER, &p_cofactor);
-         LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
-
-         if (LTC_ASN1_IS_TYPE(seq->child->next, LTC_ASN1_OBJECT_IDENTIFIER)) {
-            /* CASE 1: curve by OID (AKA short variant):
-             *   0:d=0  hl=2 l= 100 cons: SEQUENCE
-             *   2:d=1  hl=2 l=   1 prim:   INTEGER        :00
-             *   5:d=1  hl=2 l=  16 cons:   SEQUENCE       (== *seq)
-             *   7:d=2  hl=2 l=   7 prim:     OBJECT       :id-ecPublicKey
-             *  16:d=2  hl=2 l=   5 prim:     OBJECT       :(== *curve_oid (e.g. secp256k1 (== 1.3.132.0.10)))
-             *  23:d=1  hl=2 l=  77 prim:   OCTET STRING   :bytes (== *priv_key)
-             */
-            ltc_asn1_list *curve_oid = seq->child->next;
-            len = sizeof(OID);
-            if ((err = pk_oid_num_to_str(curve_oid->data, curve_oid->size, OID, &len)) != CRYPT_OK) { goto LBL_DONE; }
-            if ((err = ecc_find_curve(OID, &curve)) != CRYPT_OK)                          { goto LBL_DONE; }
-            if ((err = ecc_set_curve(curve, key)) != CRYPT_OK)                            { goto LBL_DONE; }
+         ltc_asn1_list *prime = field->child->next;
+         if ((err = mp_read_unsigned_bin(a, point->child->data, point->child->size)) != CRYPT_OK) {
+            goto LBL_DONE;
          }
-         else if ((err = der_flexi_sequence_cmp(seq->child->next, flexi_should)) == CRYPT_OK) {
-            /* CASE 2: explicit curve parameters (AKA long variant):
-             *   0:d=0  hl=3 l= 227 cons: SEQUENCE
-             *   3:d=1  hl=2 l=   1 prim:   INTEGER              :00
-             *   6:d=1  hl=3 l= 142 cons:   SEQUENCE             (== *seq)
-             *   9:d=2  hl=2 l=   7 prim:     OBJECT             :id-ecPublicKey
-             *  18:d=2  hl=3 l= 130 cons:     SEQUENCE
-             *  21:d=3  hl=2 l=   1 prim:       INTEGER          :01
-             *  24:d=3  hl=2 l=  44 cons:       SEQUENCE         (== *field)
-             *  26:d=4  hl=2 l=   7 prim:         OBJECT         :prime-field
-             *  35:d=4  hl=2 l=  33 prim:         INTEGER        :(== *prime / curve.prime)
-             *  70:d=3  hl=2 l=   6 cons:       SEQUENCE         (== *point)
-             *  72:d=4  hl=2 l=   1 prim:         OCTET STRING   :bytes (== curve.A)
-             *  75:d=4  hl=2 l=   1 prim:         OCTET STRING   :bytes (== curve.B)
-             *  78:d=3  hl=2 l=  33 prim:       OCTET STRING     :bytes (== *g_point / curve.G-point)
-             * 113:d=3  hl=2 l=  33 prim:       INTEGER          :(== *order / curve.order)
-             * 148:d=3  hl=2 l=   1 prim:       INTEGER          :(== curve.cofactor)
-             * 151:d=1  hl=2 l=  77 prim:   OCTET STRING         :bytes (== *priv_key)
-             */
-
-            if (mp_get_int(version->data) != 1) {
-               goto LBL_DONE;
-            }
-            cofactor = mp_get_int(p_cofactor->data);
-
-            if (LTC_ASN1_IS_TYPE(field->child, LTC_ASN1_OBJECT_IDENTIFIER) &&
-                LTC_ASN1_IS_TYPE(field->child->next, LTC_ASN1_INTEGER) &&
-                LTC_ASN1_IS_TYPE(point->child, LTC_ASN1_OCTET_STRING) &&
-                LTC_ASN1_IS_TYPE(point->child->next, LTC_ASN1_OCTET_STRING)) {
-
-               ltc_asn1_list *prime = field->child->next;
-               if ((err = mp_read_unsigned_bin(a, point->child->data, point->child->size)) != CRYPT_OK) {
-                  goto LBL_DONE;
-               }
-               if ((err = mp_read_unsigned_bin(b, point->child->next->data, point->child->next->size)) != CRYPT_OK) {
-                  goto LBL_DONE;
-               }
-               if ((err = ltc_ecc_import_point(point_g->data, point_g->size, prime->data, a, b, gx, gy)) != CRYPT_OK) {
-                  goto LBL_DONE;
-               }
-               if ((err = ecc_set_curve_from_mpis(a, b, prime->data, order->data, gx, gy, cofactor, key)) != CRYPT_OK) {
-                  goto LBL_DONE;
-               }
-            }
+         if ((err = mp_read_unsigned_bin(b, point->child->next->data, point->child->next->size)) != CRYPT_OK) {
+            goto LBL_DONE;
          }
-         else {
-            err = CRYPT_INVALID_PACKET;
+         if ((err = ltc_ecc_import_point(point_g->data, point_g->size, prime->data, a, b, gx, gy)) != CRYPT_OK) {
+            goto LBL_DONE;
+         }
+         if ((err = ecc_set_curve_from_mpis(a, b, prime->data, order->data, gx, gy, cofactor, key)) != CRYPT_OK) {
             goto LBL_DONE;
          }
+      }
+   } else {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_DONE;
+   }
 
-         /* load private key value 'k' */
-         len = priv_key->size;
-         if (der_decode_sequence_flexi(priv_key->data, &len, &p) == CRYPT_OK) {
-            if (p->type == LTC_ASN1_SEQUENCE &&
-                LTC_ASN1_IS_TYPE(p->child, LTC_ASN1_INTEGER) &&
-                LTC_ASN1_IS_TYPE(p->child->next, LTC_ASN1_OCTET_STRING)) {
-               ltc_asn1_list *lk = p->child->next;
-               if (mp_cmp_d(p->child->data, 1) != LTC_MP_EQ) {
-                  err = CRYPT_INVALID_PACKET;
-                  goto LBL_ECCFREE;
-               }
-               if ((err = ecc_set_key(lk->data, lk->size, PK_PRIVATE, key)) != CRYPT_OK) {
-                  goto LBL_ECCFREE;
-               }
-               goto LBL_DONE; /* success */
-            }
+   /* load private key value 'k' */
+   len = priv_key->size;
+   if (der_decode_sequence_flexi(priv_key->data, &len, &p) == CRYPT_OK) {
+      if (p->type == LTC_ASN1_SEQUENCE &&
+          LTC_ASN1_IS_TYPE(p->child, LTC_ASN1_INTEGER) &&
+          LTC_ASN1_IS_TYPE(p->child->next, LTC_ASN1_OCTET_STRING)) {
+         ltc_asn1_list *lk = p->child->next;
+         if (mp_cmp_d(p->child->data, 1) != LTC_MP_EQ) {
+            err = CRYPT_INVALID_PACKET;
+            goto LBL_ECCFREE;
          }
+         if ((err = ecc_set_key(lk->data, lk->size, PK_PRIVATE, key)) != CRYPT_OK) {
+            goto LBL_ECCFREE;
+         }
+         goto LBL_DONE; /* success */
       }
    }
    err = CRYPT_INVALID_PACKET;
@@ -148,9 +121,47 @@ LBL_ECCFREE:
    ecc_free(key);
 LBL_DONE:
    mp_clear_multi(a, b, gx, gy, LTC_NULL);
-   if (l) der_free_sequence_flexi(l);
+LBL_DER_FREE:
    if (p) der_free_sequence_flexi(p);
    return err;
 }
 
+/**
+  Import an ECC private from in PKCS#8 format
+  @param in        The packet to import from
+  @param inlen     It's length (octets)
+  @param pw_ctx    The password context when decrypting the private key
+  @param key       [out] Destination for newly imported key
+  @return CRYPT_OK if successful, upon error allocated memory is freed
+*/
+int ecc_import_pkcs8(const unsigned char *in, unsigned long inlen,
+                     const password_ctx  *pw_ctx,
+                     ecc_key *key)
+{
+   int           err;
+   ltc_asn1_list *l = NULL;
+   ltc_asn1_list *alg_id, *priv_key;
+   enum ltc_oid_id pka;
+
+   LTC_ARGCHK(key         != NULL);
+   LTC_ARGCHK(ltc_mp.name != NULL);
+
+   err = pkcs8_decode_flexi(in, inlen, pw_ctx, &l);
+   if (err != CRYPT_OK) return err;
+
+   if ((err = pkcs8_get_children(l, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
+      goto LBL_DER_FREE;
+   }
+   if (pka != LTC_OID_EC) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_DER_FREE;
+   }
+
+   err = ecc_import_pkcs8_asn1(alg_id, priv_key, key);
+
+LBL_DER_FREE:
+   der_free_sequence_flexi(l);
+   return err;
+}
+
 #endif

+ 14 - 9
src/pk/ed25519/ed25519_import_pkcs8.c

@@ -9,20 +9,25 @@
 
 #ifdef LTC_CURVE25519
 
+int ed25519_import_pkcs8_asn1(ltc_asn1_list  *alg_id, ltc_asn1_list *priv_key,
+                              curve25519_key *key)
+{
+   return ec25519_import_pkcs8_asn1(alg_id, priv_key, LTC_OID_ED25519, key);
+}
+
 /**
   Import an Ed25519 private key in PKCS#8 format
-  @param in        The DER-encoded PKCS#8-formatted private key
-  @param inlen     The length of the input data
-  @param passwd    The password to decrypt the private key
-  @param passwdlen Password's length (octets)
-  @param key       [out] Where to import the key to
+  @param in        The packet to import from
+  @param inlen     It's length (octets)
+  @param pw_ctx    The password context when decrypting the private key
+  @param key       [out] Destination for newly imported key
   @return CRYPT_OK if successful, on error all allocated memory is freed automatically
 */
-int ed25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
-                                  const void *pwd, unsigned long pwdlen,
-                              curve25519_key *key)
+int ed25519_import_pkcs8(const unsigned char  *in, unsigned long inlen,
+                         const password_ctx   *pw_ctx,
+                               curve25519_key *key)
 {
-   return ec25519_import_pkcs8(in, inlen, pwd, pwdlen, LTC_OID_ED25519, tweetnacl_crypto_sk_to_pk, key);
+   return ec25519_import_pkcs8(in, inlen, pw_ctx, LTC_OID_ED25519, key);
 }
 
 #endif

+ 36 - 82
src/pk/rsa/rsa_import_pkcs8.c

@@ -9,107 +9,61 @@
 
 #ifdef LTC_MRSA
 
-/* Public-Key Cryptography Standards (PKCS) #8:
- * Private-Key Information Syntax Specification Version 1.2
- * https://tools.ietf.org/html/rfc5208
- *
- * PrivateKeyInfo ::= SEQUENCE {
- *      version                   Version,
- *      privateKeyAlgorithm       PrivateKeyAlgorithmIdentifier,
- *      privateKey                PrivateKey,
- *      attributes           [0]  IMPLICIT Attributes OPTIONAL }
- * where:
- * - Version ::= INTEGER
- * - PrivateKeyAlgorithmIdentifier ::= AlgorithmIdentifier
- * - PrivateKey ::= OCTET STRING
- * - Attributes ::= SET OF Attribute
- *
- * EncryptedPrivateKeyInfo ::= SEQUENCE {
- *        encryptionAlgorithm  EncryptionAlgorithmIdentifier,
- *        encryptedData        EncryptedData }
- * where:
- * - EncryptionAlgorithmIdentifier ::= AlgorithmIdentifier
- * - EncryptedData ::= OCTET STRING
- */
+int rsa_import_pkcs8_asn1(ltc_asn1_list *alg_id, ltc_asn1_list *priv_key, rsa_key *key)
+{
+   int           err;
+
+   LTC_ARGCHK(key != NULL);
+
+   LTC_UNUSED_PARAM(alg_id);
+
+   if ((err = rsa_init(key)) != CRYPT_OK) {
+      return err;
+   }
+
+   if ((err = rsa_import_pkcs1(priv_key->data, priv_key->size, key)) != CRYPT_OK) {
+      rsa_free(key);
+      return err;
+   }
+   key->type = PK_PRIVATE;
+
+   return err;
+}
 
 /**
   Import an RSAPrivateKey in PKCS#8 format
   @param in        The packet to import from
   @param inlen     It's length (octets)
-  @param passwd    The password for decrypting privkey
-  @param passwdlen Password's length (octets)
+  @param pw_ctx    The password context when decrypting the private key
   @param key       [out] Destination for newly imported key
   @return CRYPT_OK if successful, upon error allocated memory is freed
 */
 int rsa_import_pkcs8(const unsigned char *in, unsigned long inlen,
-                     const void *passwd, unsigned long passwdlen,
+                     const password_ctx  *pw_ctx,
                      rsa_key *key)
 {
    int           err;
-   unsigned char *buf1 = NULL, *buf2 = NULL;
-   unsigned long buf1len, buf2len;
-   unsigned long oid[16], version;
-   const char    *rsaoid;
-   ltc_asn1_list alg_seq[2], top_seq[3];
    ltc_asn1_list *l = NULL;
-   unsigned char *decrypted = NULL;
-   unsigned long decryptedlen;
-
-   LTC_ARGCHK(in          != NULL);
-   LTC_ARGCHK(key         != NULL);
-   LTC_ARGCHK(ltc_mp.name != NULL);
-
-   /* get RSA alg oid */
-   err = pk_get_oid(LTC_OID_RSA, &rsaoid);
-   if (err != CRYPT_OK) { goto LBL_NOFREE; }
-
-   /* alloc buffers */
-   buf1len = inlen; /* approx. */
-   buf1 = XMALLOC(buf1len);
-   if (buf1 == NULL) { err = CRYPT_MEM; goto LBL_NOFREE; }
-   buf2len = inlen; /* approx. */
-   buf2 = XMALLOC(buf2len);
-   if (buf2 == NULL) { err = CRYPT_MEM; goto LBL_FREE1; }
+   ltc_asn1_list *alg_id, *priv_key;
+   enum ltc_oid_id pka;
 
-   /* init key */
-   if ((err = rsa_init(key)) != CRYPT_OK) { goto LBL_FREE2; }
+   LTC_ARGCHK(in != NULL);
 
-   /* try to decode encrypted priv key */
-   if ((err = pkcs8_decode_flexi(in, inlen, passwd, passwdlen, &l)) != CRYPT_OK) {
-      goto LBL_ERR;
+   if ((err = pkcs8_decode_flexi(in, inlen, pw_ctx, &l)) != CRYPT_OK) {
+      return err;
    }
-   decrypted    = l->data;
-   decryptedlen = l->size;
-
-   /* try to decode unencrypted priv key */
-   LTC_SET_ASN1(alg_seq, 0, LTC_ASN1_OBJECT_IDENTIFIER, oid, 16UL);
-   LTC_SET_ASN1(alg_seq, 1, LTC_ASN1_NULL, NULL, 0UL);
-   LTC_SET_ASN1(top_seq, 0, LTC_ASN1_SHORT_INTEGER, &version, 1UL);
-   LTC_SET_ASN1(top_seq, 1, LTC_ASN1_SEQUENCE, alg_seq, 2UL);
-   LTC_SET_ASN1(top_seq, 2, LTC_ASN1_OCTET_STRING, buf1, buf1len);
-   err=der_decode_sequence(decrypted, decryptedlen, top_seq, 3UL);
-   if (err != CRYPT_OK) { goto LBL_ERR; }
-
-   /* check alg oid */
-   if ((err = pk_oid_cmp_with_asn1(rsaoid, &alg_seq[0])) != CRYPT_OK) {
-      goto LBL_ERR;
+   if ((err = pkcs8_get_children(l, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
+      goto LBL_DER_FREE;
    }
-
-   if ((err = rsa_import_pkcs1(buf1, top_seq[2].size, key)) != CRYPT_OK) {
-      goto LBL_ERR;
+   if (pka != LTC_OID_RSA) {
+      err = CRYPT_INVALID_PACKET;
+      goto LBL_DER_FREE;
    }
-   key->type = PK_PRIVATE;
-   err = CRYPT_OK;
-   goto LBL_FREE2;
 
-LBL_ERR:
-   rsa_free(key);
-LBL_FREE2:
-   if (l) der_free_sequence_flexi(l);
-   XFREE(buf2);
-LBL_FREE1:
-   XFREE(buf1);
-LBL_NOFREE:
+   err = rsa_import_pkcs8_asn1(alg_id, priv_key, key);
+
+LBL_DER_FREE:
+   der_free_sequence_flexi(l);
    return err;
 }
 

+ 13 - 9
src/pk/x25519/x25519_import_pkcs8.c

@@ -9,20 +9,24 @@
 
 #ifdef LTC_CURVE25519
 
+int x25519_import_pkcs8_asn1(ltc_asn1_list  *alg_id, ltc_asn1_list *priv_key,
+                             curve25519_key *key)
+{
+   return ec25519_import_pkcs8_asn1(alg_id, priv_key, LTC_OID_X25519, key);
+}
 /**
   Import a X25519 private key in PKCS#8 format
-  @param in        The DER-encoded PKCS#8-formatted private key
-  @param inlen     The length of the input data
-  @param passwd    The password to decrypt the private key
-  @param passwdlen Password's length (octets)
-  @param key       [out] Where to import the key to
+  @param in        The packet to import from
+  @param inlen     It's length (octets)
+  @param pw_ctx    The password context when decrypting the private key
+  @param key       [out] Destination for newly imported key
   @return CRYPT_OK if successful, on error all allocated memory is freed automatically
 */
-int x25519_import_pkcs8(const unsigned char *in, unsigned long inlen,
-                       const void *pwd, unsigned long pwdlen,
-                       curve25519_key *key)
+int x25519_import_pkcs8(const unsigned char  *in, unsigned long inlen,
+                        const password_ctx   *pw_ctx,
+                              curve25519_key *key)
 {
-   return ec25519_import_pkcs8(in, inlen, pwd, pwdlen, LTC_OID_X25519, tweetnacl_crypto_scalarmult_base, key);
+   return ec25519_import_pkcs8(in, inlen, pw_ctx, LTC_OID_X25519, key);
 }
 
 #endif

+ 28 - 17
tests/ecc_test.c

@@ -637,6 +637,15 @@ static int s_ecc_new_api(void)
    return CRYPT_OK;
 }
 
+
+static int password_get(void **p, unsigned long *l, void *u)
+{
+   LTC_UNUSED_PARAM(u);
+   *p = strdup("secret");
+   *l = 6;
+   return 0;
+}
+
 static int s_ecc_import_export(void) {
    const ltc_ecc_curve *cu;
    ecc_key key, pri, pub;
@@ -1317,6 +1326,8 @@ static int s_ecc_import_export(void) {
       0x9d, 0x7b, 0x70, 0x3e, 0xf5, 0x7d, 0xa4, 0xfd, 0x3c, 0xc6, 0x49, 0x93, 0xd3, 0x5b, 0xef, 0xc9,
       0xae, 0x97, 0xaf, 0x64, 0x64, 0xf9, 0x69, 0xd8
    };
+   password_ctx pw_ctx;
+   pw_ctx.callback = password_get;
 
    if (ltc_mp.sqrtmod_prime == NULL) return CRYPT_NOP; /* we need compressed points which requires sqrtmod_prime */
 
@@ -1365,84 +1376,84 @@ static int s_ecc_import_export(void) {
    ecc_free(&key);
 
    /* import - private PKCS8 format - no password */
-   DO(ecc_import_pkcs8(long_pri_pkcs8, sizeof(long_pri_pkcs8),   NULL, 0, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8, sizeof(long_pri_pkcs8),   NULL, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
-   DO(ecc_import_pkcs8(long_pric_pkcs8, sizeof(long_pric_pkcs8),  NULL, 0, &key));
+   DO(ecc_import_pkcs8(long_pric_pkcs8, sizeof(long_pric_pkcs8),  NULL, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
-   DO(ecc_import_pkcs8(short_pri_pkcs8, sizeof(short_pri_pkcs8),  NULL, 0, &key));
+   DO(ecc_import_pkcs8(short_pri_pkcs8, sizeof(short_pri_pkcs8),  NULL, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
-   DO(ecc_import_pkcs8(short_pric_pkcs8, sizeof(short_pric_pkcs8), NULL, 0, &key));
+   DO(ecc_import_pkcs8(short_pric_pkcs8, sizeof(short_pric_pkcs8), NULL, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 
    /* import - private PKCS8 format - password protected (PBES1 algorithms) */
 #ifdef LTC_MD2
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_md2_des, sizeof(long_pri_pkcs8_pbe_md2_des), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_md2_des, sizeof(long_pri_pkcs8_pbe_md2_des), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #ifdef LTC_MD5
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_md5_des, sizeof(long_pri_pkcs8_pbe_md5_des), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_md5_des, sizeof(long_pri_pkcs8_pbe_md5_des), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #ifdef LTC_SHA1
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_sha1_des, sizeof(long_pri_pkcs8_pbe_sha1_des), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_sha1_des, sizeof(long_pri_pkcs8_pbe_sha1_des), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #if defined(LTC_RC2) && defined(LTC_MD2)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_md2_rc2_64, sizeof(long_pri_pkcs8_pbe_md2_rc2_64), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_md2_rc2_64, sizeof(long_pri_pkcs8_pbe_md2_rc2_64), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #if defined(LTC_RC2) && defined(LTC_MD5)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_md5_rc2_64, sizeof(long_pri_pkcs8_pbe_md5_rc2_64), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_md5_rc2_64, sizeof(long_pri_pkcs8_pbe_md5_rc2_64), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #if defined(LTC_RC2) && defined(LTC_SHA1)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_sha1_rc2_64, sizeof(long_pri_pkcs8_pbe_sha1_rc2_64), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbe_sha1_rc2_64, sizeof(long_pri_pkcs8_pbe_sha1_rc2_64), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 
    /* import - private PKCS8 format - password protected (PBES2 algorithms) */
 #if defined(LTC_RC2)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_rc2_cbc, sizeof(long_pri_pkcs8_pbkdf2_rc2_cbc), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_rc2_cbc, sizeof(long_pri_pkcs8_pbkdf2_rc2_cbc), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #if defined(LTC_DES)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_des_cbc, sizeof(long_pri_pkcs8_pbkdf2_des_cbc), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_des_cbc, sizeof(long_pri_pkcs8_pbkdf2_des_cbc), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #if defined(LTC_DES)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_des_ede3_cbc), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_des_ede3_cbc), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #if defined(LTC_SHA224) && defined(LTC_DES)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_sha224_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_sha224_des_ede3_cbc), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_sha224_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_sha224_des_ede3_cbc), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #if defined(LTC_SHA256) && defined(LTC_DES)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_sha256_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_sha256_des_ede3_cbc), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_sha256_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_sha256_des_ede3_cbc), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #if defined(LTC_SHA384) && defined(LTC_DES)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_sha384_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_sha384_des_ede3_cbc), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_sha384_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_sha384_des_ede3_cbc), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif
 #if defined(LTC_SHA512) && defined(LTC_DES)
-   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_sha512_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_sha512_des_ede3_cbc), "secret", 6, &key));
+   DO(ecc_import_pkcs8(long_pri_pkcs8_pbkdf2_sha512_des_ede3_cbc, sizeof(long_pri_pkcs8_pbkdf2_sha512_des_ede3_cbc), &pw_ctx, &key));
    DO(s_ecc_key_cmp(PK_PRIVATE, &pri, &key));
    ecc_free(&key);
 #endif

+ 12 - 2
tests/ed25519_test.c

@@ -16,6 +16,14 @@ static void xor_shuffle(unsigned char *buf, unsigned long size, unsigned char ch
       buf[i] ^= change;
 }
 
+static int password_get(void **p, unsigned long *l, void *u)
+{
+   LTC_UNUSED_PARAM(u);
+   *p = strdup("123456");
+   *l = 6;
+   return 0;
+}
+
 static int s_rfc_8410_10_test(void)
 {
    const struct {
@@ -57,6 +65,8 @@ static int s_rfc_8410_10_test(void)
    unsigned char buf[1024];
    char tmp[512];
    unsigned long buflen, tmplen;
+   password_ctx pw_ctx;
+   pw_ctx.callback = password_get;
    for (n = 0; n < sizeof(rfc_8410_10)/sizeof(rfc_8410_10[0]); ++n) {
       buflen = sizeof(buf);
       DO(base64_decode(rfc_8410_10[n].b64, XSTRLEN(rfc_8410_10[n].b64), buf, &buflen));
@@ -69,10 +79,10 @@ static int s_rfc_8410_10_test(void)
             break;
          case 2:
          case 3:
-            DO(ed25519_import_pkcs8(buf, buflen, NULL, 0, &key));
+            DO(ed25519_import_pkcs8(buf, buflen, NULL, &key));
             break;
          case 4:
-            DO(ed25519_import_pkcs8(buf, buflen, "123456", 6, &key));
+            DO(ed25519_import_pkcs8(buf, buflen, &pw_ctx, &key));
             break;
          default:
             return CRYPT_FAIL_TESTVECTOR;

+ 12 - 2
tests/rsa_test.c

@@ -227,7 +227,7 @@ static int rsa_compat_test(void)
    rsa_free(&key);
 
    /* try import private key in pkcs8 format */
-   DO(rsa_import_pkcs8(pkcs8_private_rsa, sizeof(pkcs8_private_rsa), NULL, 0, &key));
+   DO(rsa_import_pkcs8(pkcs8_private_rsa, sizeof(pkcs8_private_rsa), NULL, &key));
    len = sizeof(buf);
    DO(rsa_export(buf, &len, PK_PRIVATE, &key));
    DO(do_compare_testvector(buf, len, openssl_private_rsa, sizeof(openssl_private_rsa), "RSA private export (from PKCS#8)", 0));
@@ -430,9 +430,19 @@ static int s_rsa_import_x509(const void *in, unsigned long inlen, void *key)
 }
 
 #if defined(LTC_MD2) && defined(LTC_MD5) && defined(LTC_RC2)
+static int password_get(void **p, unsigned long *l, void *u)
+{
+   LTC_UNUSED_PARAM(u);
+   *p = strdup("secret");
+   *l = 6;
+   return 0;
+}
+
 static int s_rsa_import_pkcs8(const void *in, unsigned long inlen, void *key)
 {
-   return rsa_import_pkcs8(in, inlen, "secret", 6, key);
+   password_ctx pw_ctx;
+   pw_ctx.callback = password_get;
+   return rsa_import_pkcs8(in, inlen, &pw_ctx, key);
 }
 #endif
 #endif

+ 15 - 5
tests/x25519_test.c

@@ -139,6 +139,13 @@ static int s_rfc_8410_10_test(void)
    return CRYPT_OK;
 }
 
+static int password_get(void **p, unsigned long *l, void *u)
+{
+   *p = strdup(u);
+   *l = strlen(*p);
+   return 0;
+}
+
 static int s_x25519_pkcs8_test(void)
 {
    const struct {
@@ -161,13 +168,16 @@ static int s_x25519_pkcs8_test(void)
    unsigned n;
    curve25519_key key;
    unsigned char buf[1024];
-   unsigned long buflen, passlen;
+   unsigned long buflen;
+   password_ctx pw_ctx, *p_pw_ctx;
+   pw_ctx.callback = password_get;
    for (n = 0; n < sizeof(s_x25519_pkcs8)/sizeof(s_x25519_pkcs8[0]); ++n) {
       buflen = sizeof(buf);
       DO(base64_decode(s_x25519_pkcs8[n].b64, XSTRLEN(s_x25519_pkcs8[n].b64), buf, &buflen));
-      if (s_x25519_pkcs8[n].pass != NULL) passlen = XSTRLEN(s_x25519_pkcs8[n].pass);
-      else passlen = 0;
-      DO(x25519_import_pkcs8(buf, buflen, s_x25519_pkcs8[n].pass, passlen, &key));
+      pw_ctx.userdata = (void*)s_x25519_pkcs8[n].pass;
+      if (s_x25519_pkcs8[n].pass != NULL) p_pw_ctx = &pw_ctx;
+      else p_pw_ctx = NULL;
+      DO(x25519_import_pkcs8(buf, buflen, p_pw_ctx, &key));
       zeromem(buf, sizeof(buf));
    }
    return CRYPT_OK;
@@ -187,7 +197,7 @@ static int s_x25519_compat_test(void)
    DO(x25519_make_key(&yarrow_prng, prng_idx, &priv));
 
    DO(x25519_export(buf, &buflen, PK_PRIVATE | PK_STD, &priv));
-   DO(x25519_import_pkcs8(buf, buflen, NULL, 0, &imported));
+   DO(x25519_import_pkcs8(buf, buflen, NULL, &imported));
    DO(do_compare_testvector(&priv, sizeof(priv), &imported, sizeof(imported), "priv after ex-&import", __LINE__));
    XMEMSET(&imported, 0, sizeof(imported));