Browse Source

add real pkcs#8 import of Curve25519 private keys

Steffen Jaeckel 6 years ago
parent
commit
e3766e16ca

+ 6 - 0
src/headers/tomcrypt_pk.h

@@ -359,6 +359,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(const unsigned char *in, unsigned long inlen, curve25519_key *key);
 int ed25519_import_x509(const unsigned char *in, unsigned long inlen, 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_sign(const unsigned char  *msg, unsigned long msglen,
 int ed25519_sign(const unsigned char  *msg, unsigned long msglen,
                        unsigned char  *sig, unsigned long *siglen,
                        unsigned char  *sig, unsigned long *siglen,
@@ -381,6 +384,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(const unsigned char *in, unsigned long inlen, curve25519_key *key);
 int x25519_import_x509(const unsigned char *in, unsigned long inlen, 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_shared_secret(const curve25519_key *private_key,
 int x25519_shared_secret(const curve25519_key *private_key,
                          const curve25519_key *public_key,
                          const curve25519_key *public_key,

+ 6 - 0
src/headers/tomcrypt_private.h

@@ -315,6 +315,12 @@ int crypto_sk_to_pk(unsigned char *pk, const unsigned char *sk);
 int crypto_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
 int crypto_scalarmult(unsigned char *q, const unsigned char *n, const unsigned char *p);
 int crypto_scalarmult_base(unsigned char *q,const unsigned char *n);
 int crypto_scalarmult_base(unsigned char *q,const unsigned char *n);
 
 
+typedef int (*sk_to_pk)(unsigned char *pk ,const unsigned char *sk);
+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);
+
 #endif /* LTC_CURVE25519 */
 #endif /* LTC_CURVE25519 */
 
 
 #ifdef LTC_DER
 #ifdef LTC_DER

+ 97 - 0
src/pk/ec25519/ec25519_import_pkcs8.c

@@ -0,0 +1,97 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt_private.h"
+
+/**
+  @file ec25519_import_pkcs8.c
+  Generic import of a Curve/Ed25519 private key in PKCS#8 format, Steffen Jaeckel
+*/
+
+#ifdef LTC_CURVE25519
+
+/**
+  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
+  @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)
+{
+   int err = CRYPT_INVALID_ARG;
+   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_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid) / sizeof(tmpoid[0]));
+
+      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;
+         }
+      }
+
+      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;
+      }
+   }
+out:
+   if (l) der_free_sequence_flexi(l);
+#ifdef LTC_CLEAN_STACK
+   zeromem(private_key, sizeof(private_key));
+#endif
+
+   return err;
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 3 - 56
src/pk/ed25519/ed25519_import.c

@@ -16,7 +16,7 @@
 #ifdef LTC_CURVE25519
 #ifdef LTC_CURVE25519
 
 
 /**
 /**
-  Import a Ed25519 key from a binary packet
+  Import an Ed25519 public key
   @param in     The packet to read
   @param in     The packet to read
   @param inlen  The length of the input packet
   @param inlen  The length of the input packet
   @param key    [out] Where to import the key to
   @param key    [out] Where to import the key to
@@ -25,72 +25,19 @@
 int ed25519_import(const unsigned char *in, unsigned long inlen, curve25519_key *key)
 int ed25519_import(const unsigned char *in, unsigned long inlen, curve25519_key *key)
 {
 {
    int err;
    int err;
-   const char* oid;
-   ltc_asn1_list alg_id[1];
-   unsigned char private_key[34];
-   unsigned long version, key_len;
-   unsigned long tmpoid[16];
+   unsigned long key_len;
 
 
    LTC_ARGCHK(in  != NULL);
    LTC_ARGCHK(in  != NULL);
    LTC_ARGCHK(key != NULL);
    LTC_ARGCHK(key != NULL);
 
 
-   /* There's only one case where the inlen is equal to the pubkey-size
-    * and that's a raw pubkey, so let's just do a raw import.
-    */
-   if (inlen == sizeof(key->pub)) {
-      XMEMCPY(key->pub, in, sizeof(key->pub));
-      key->type = PK_PUBLIC;
-      key->algo = PKA_ED25519;
-      return CRYPT_OK;
-   }
-
    key_len = sizeof(key->pub);
    key_len = sizeof(key->pub);
    if ((err = x509_decode_subject_public_key_info(in, inlen, PKA_ED25519, key->pub, &key_len, LTC_ASN1_EOL, NULL, 0uL)) == CRYPT_OK) {
    if ((err = x509_decode_subject_public_key_info(in, inlen, PKA_ED25519, key->pub, &key_len, LTC_ASN1_EOL, NULL, 0uL)) == CRYPT_OK) {
       key->type = PK_PUBLIC;
       key->type = PK_PUBLIC;
       key->algo = PKA_ED25519;
       key->algo = PKA_ED25519;
       return CRYPT_OK;
       return CRYPT_OK;
-   }
-
-   LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0]));
-
-   key_len = sizeof(private_key);
-   err = der_decode_sequence_multi(in, inlen,
-                                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);
-   if (err != CRYPT_OK) {
-      if ((err == CRYPT_INPUT_TOO_LONG) && (version == 1)) {
-         version = 0;
-      } else {
-         goto out;
-      }
-   }
-
-   if ((err = pk_get_oid(PKA_ED25519, &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) {
-         crypto_sk_to_pk(key->pub, key->priv);
-         key->type = PK_PRIVATE;
-         key->algo = PKA_ED25519;
-      }
    } else {
    } else {
-      err = CRYPT_PK_INVALID_TYPE;
+      return err;
    }
    }
-
-out:
-#ifdef LTC_CLEAN_STACK
-   zeromem(private_key, sizeof(private_key));
-#endif
-
-   return err;
 }
 }
 
 
 #endif
 #endif

+ 38 - 0
src/pk/ed25519/ed25519_import_pkcs8.c

@@ -0,0 +1,38 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt_private.h"
+
+/**
+  @file ed25519_import_pkcs8.c
+  Import a Ed25519 key in PKCS#8 format, Steffen Jaeckel
+*/
+
+#ifdef LTC_CURVE25519
+
+/**
+  Import a 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
+  @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)
+{
+   return ec25519_import_pkcs8(in, inlen, pwd, pwdlen, PKA_ED25519, crypto_sk_to_pk, key);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 2 - 40
src/pk/x25519/x25519_import.c

@@ -25,11 +25,7 @@
 int x25519_import(const unsigned char *in, unsigned long inlen, curve25519_key *key)
 int x25519_import(const unsigned char *in, unsigned long inlen, curve25519_key *key)
 {
 {
    int err;
    int err;
-   const char *oid;
-   ltc_asn1_list alg_id[1];
-   unsigned char private_key[34];
-   unsigned long version, key_len;
-   unsigned long tmpoid[16];
+   unsigned long key_len;
 
 
    LTC_ARGCHK(in  != NULL);
    LTC_ARGCHK(in  != NULL);
    LTC_ARGCHK(key != NULL);
    LTC_ARGCHK(key != NULL);
@@ -49,43 +45,9 @@ int x25519_import(const unsigned char *in, unsigned long inlen, curve25519_key *
       key->type = PK_PUBLIC;
       key->type = PK_PUBLIC;
       key->algo = PKA_X25519;
       key->algo = PKA_X25519;
       return CRYPT_OK;
       return CRYPT_OK;
-   }
-
-   LTC_SET_ASN1(alg_id, 0, LTC_ASN1_OBJECT_IDENTIFIER, tmpoid, sizeof(tmpoid)/sizeof(tmpoid[0]));
-
-   key_len = sizeof(private_key);
-   if ((err = der_decode_sequence_multi(in, inlen,
-                             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) {
-      goto out;
-   }
-
-   if ((err = pk_get_oid(PKA_X25519, &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) {
-         crypto_scalarmult_base(key->pub, key->priv);
-         key->type = PK_PRIVATE;
-         key->algo = PKA_X25519;
-      }
    } else {
    } else {
-      err = CRYPT_PK_INVALID_TYPE;
+      return err;
    }
    }
-
-out:
-#ifdef LTC_CLEAN_STACK
-   zeromem(private_key, sizeof(private_key));
-#endif
-
-   return err;
 }
 }
 
 
 #endif
 #endif

+ 38 - 0
src/pk/x25519/x25519_import_pkcs8.c

@@ -0,0 +1,38 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ */
+#include "tomcrypt_private.h"
+
+/**
+  @file x25519_import_pkcs8.c
+  Import a X25519 key in PKCS#8 format, Steffen Jaeckel
+*/
+
+#ifdef LTC_CURVE25519
+
+/**
+  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
+  @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)
+{
+   return ec25519_import_pkcs8(in, inlen, pwd, pwdlen, PKA_X25519, crypto_scalarmult_base, key);
+}
+
+#endif
+
+/* ref:         $Format:%D$ */
+/* git commit:  $Format:%H$ */
+/* commit time: $Format:%ai$ */

+ 23 - 4
tests/ed25519_test.c

@@ -43,6 +43,13 @@ static int _rfc_8410_10_test(void)
                        { "MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC"
                        { "MHICAQEwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC"
                          "oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB"
                          "oB8wHQYKKoZIhvcNAQkJFDEPDA1DdXJkbGUgQ2hhaXJzgSEAGb9ECWmEzf6FQbrB"
                          "Z9w7lshQhqowtrbLDFw4rXAxZuE=", -1 },
                          "Z9w7lshQhqowtrbLDFw4rXAxZuE=", -1 },
+                         /* Another self-created testvector.
+                          * `openssl genpkey -algorithm ed25519 -pass stdin -aes128`
+                          */
+                       { "MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAiFflnrBOdwjwICCAAw"
+                         "DAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEMzFYoqiT6gxwFx2EA55MUYEQFD1"
+                         "ZLxPNhm4YAsMZaxu5qpLjiZbkWsTHxURb6WhSW8GAbNbTwxeOaA02sUhJg8rx44/"
+                         "N9PzN2QGzIQ1Yv/vHqQ=", -1 },
    };
    };
    unsigned n;
    unsigned n;
    curve25519_key key;
    curve25519_key key;
@@ -52,10 +59,22 @@ static int _rfc_8410_10_test(void)
    for (n = 0; n < sizeof(rfc_8410_10)/sizeof(rfc_8410_10[0]); ++n) {
    for (n = 0; n < sizeof(rfc_8410_10)/sizeof(rfc_8410_10[0]); ++n) {
       buflen = sizeof(buf);
       buflen = sizeof(buf);
       DO(base64_decode(rfc_8410_10[n].b64, strlen(rfc_8410_10[n].b64), buf, &buflen));
       DO(base64_decode(rfc_8410_10[n].b64, strlen(rfc_8410_10[n].b64), buf, &buflen));
-      if (rfc_8410_10[n].type == -2) {
-         DO(ed25519_import_x509(buf, buflen, &key));
-      } else {
-         DO(ed25519_import(buf, buflen, &key));
+      switch (n) {
+         case 0:
+            DO(ed25519_import(buf, buflen, &key));
+            break;
+         case 1:
+            DO(ed25519_import_x509(buf, buflen, &key));
+            break;
+         case 2:
+         case 3:
+            DO(ed25519_import_pkcs8(buf, buflen, NULL, 0, &key));
+            break;
+         case 4:
+            DO(ed25519_import_pkcs8(buf, buflen, "123456", 6, &key));
+            break;
+         default:
+            return CRYPT_FAIL_TESTVECTOR;
       }
       }
       zeromem(buf, sizeof(buf));
       zeromem(buf, sizeof(buf));
       if (rfc_8410_10[n].type > 0) {
       if (rfc_8410_10[n].type > 0) {

+ 41 - 3
tests/x25519_test.c

@@ -120,7 +120,7 @@ static int _rfc_7748_6_test(void)
 static int _rfc_8410_10_test(void)
 static int _rfc_8410_10_test(void)
 {
 {
    const struct {
    const struct {
-      const char* b64;
+      const char *b64;
    } rfc_8410_10[] = {
    } rfc_8410_10[] = {
                          /* RFC 8410 - 10.2.  Example X25519 Certificate */
                          /* RFC 8410 - 10.2.  Example X25519 Certificate */
                        { "MIIBLDCB36ADAgECAghWAUdKKo3DMDAFBgMrZXAwGTEXMBUGA1UEAwwOSUVURiBUZX"
                        { "MIIBLDCB36ADAgECAghWAUdKKo3DMDAFBgMrZXAwGTEXMBUGA1UEAwwOSUVURiBUZX"
@@ -129,7 +129,8 @@ static int _rfc_8410_10_test(void)
                          "ga9OukqY6qm05qo0UwQzAPBgNVHRMBAf8EBTADAQEAMA4GA1UdDwEBAAQEAwIDCDAg"
                          "ga9OukqY6qm05qo0UwQzAPBgNVHRMBAf8EBTADAQEAMA4GA1UdDwEBAAQEAwIDCDAg"
                          "BgNVHQ4BAQAEFgQUmx9e7e0EM4Xk97xiPFl1uQvIuzswBQYDK2VwA0EAryMB/t3J5v"
                          "BgNVHQ4BAQAEFgQUmx9e7e0EM4Xk97xiPFl1uQvIuzswBQYDK2VwA0EAryMB/t3J5v"
                          "/BzKc9dNZIpDmAgs3babFOTQbs+BolzlDUwsPrdGxO3YNGhW7Ibz3OGhhlxXrCe1Cg"
                          "/BzKc9dNZIpDmAgs3babFOTQbs+BolzlDUwsPrdGxO3YNGhW7Ibz3OGhhlxXrCe1Cg"
-                         "w1AH9efZBw==" },
+                         "w1AH9efZBw=="
+                       },
    };
    };
    unsigned n;
    unsigned n;
    curve25519_key key;
    curve25519_key key;
@@ -144,6 +145,40 @@ static int _rfc_8410_10_test(void)
    return CRYPT_OK;
    return CRYPT_OK;
 }
 }
 
 
+static int _x25519_pkcs8_test(void)
+{
+   const struct {
+      const char *b64, *pass;
+   } _x25519_pkcs8[] = {
+                          /* `openssl genpkey -algorithm x25519 -pass stdin -aes128` */
+                          {
+                            "MIGbMFcGCSqGSIb3DQEFDTBKMCkGCSqGSIb3DQEFDDAcBAjG5kRkEihOvQICCAAw"
+                            "DAYIKoZIhvcNAgkFADAdBglghkgBZQMEAQIEEHPLHLoCvesRyeToyMtGHWcEQM1+"
+                            "FMpSO5DplX3d+YGTAvf0WxWaBff1q4bfKDn/7IoWQT1e4Fe6Psj62Vy9T69o3+Uy"
+                            "VM6mdIOXGOkAtaMSsSk=",
+                            "123456"
+                          },
+                          /* `openssl genpkey -algorithm x25519 -pass stdin` */
+                          {
+                            "MC4CAQAwBQYDK2VuBCIEIEAInaUdx+fQFfghpCzw/WdItRT3+FnPSkrU9TcIZTZW",
+                            NULL
+                          },
+   };
+   unsigned n;
+   curve25519_key key;
+   unsigned char buf[1024];
+   unsigned long buflen, passlen;
+   for (n = 0; n < sizeof(_x25519_pkcs8)/sizeof(_x25519_pkcs8[0]); ++n) {
+      buflen = sizeof(buf);
+      DO(base64_decode(_x25519_pkcs8[n].b64, strlen(_x25519_pkcs8[n].b64), buf, &buflen));
+      if (_x25519_pkcs8[n].pass != NULL) passlen = strlen(_x25519_pkcs8[n].pass);
+      else passlen = 0;
+      DO(x25519_import_pkcs8(buf, buflen, _x25519_pkcs8[n].pass, passlen, &key));
+      zeromem(buf, sizeof(buf));
+   }
+   return CRYPT_OK;
+}
+
 static int _x25519_compat_test(void)
 static int _x25519_compat_test(void)
 {
 {
    curve25519_key priv, pub, imported;
    curve25519_key priv, pub, imported;
@@ -158,7 +193,7 @@ static int _x25519_compat_test(void)
    DO(x25519_make_key(&yarrow_prng, prng_idx, &priv));
    DO(x25519_make_key(&yarrow_prng, prng_idx, &priv));
 
 
    DO(x25519_export(buf, &buflen, PK_PRIVATE, &priv));
    DO(x25519_export(buf, &buflen, PK_PRIVATE, &priv));
-   DO(x25519_import(buf, buflen, &imported));
+   DO(x25519_import_pkcs8(buf, buflen, NULL, 0, &imported));
    DO(do_compare_testvector(&priv, sizeof(priv), &imported, sizeof(imported), "priv after ex-&import", __LINE__));
    DO(do_compare_testvector(&priv, sizeof(priv), &imported, sizeof(imported), "priv after ex-&import", __LINE__));
    XMEMSET(&imported, 0, sizeof(imported));
    XMEMSET(&imported, 0, sizeof(imported));
 
 
@@ -201,6 +236,9 @@ int x25519_test(void)
    if ((ret = _rfc_8410_10_test()) != CRYPT_OK) {
    if ((ret = _rfc_8410_10_test()) != CRYPT_OK) {
       return ret;
       return ret;
    }
    }
+   if ((ret = _x25519_pkcs8_test()) != CRYPT_OK) {
+      return ret;
+   }
    if ((ret = _x25519_compat_test()) != CRYPT_OK) {
    if ((ret = _x25519_compat_test()) != CRYPT_OK) {
       return ret;
       return ret;
    }
    }