Browse Source

Merge pull request #699 from libtom/some-improvements

Some improvements
Steffen Jaeckel 3 weeks ago
parent
commit
03881e4abc

+ 8 - 0
libtomcrypt_VS2008.vcproj

@@ -2281,6 +2281,14 @@
 						RelativePath="src\pk\asn1\x509\x509_encode_subject_public_key_info.c"
 						>
 					</File>
+					<File
+						RelativePath="src\pk\asn1\x509\x509_get_pka.c"
+						>
+					</File>
+					<File
+						RelativePath="src\pk\asn1\x509\x509_import_spki.c"
+						>
+					</File>
 				</Filter>
 			</Filter>
 			<Filter

+ 4 - 3
makefile.mingw

@@ -176,9 +176,10 @@ src/pk/asn1/oid/pk_get.o src/pk/asn1/oid/pk_oid_cmp.o src/pk/asn1/oid/pk_oid_str
 src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/pkcs8/pkcs8_get.o \
 src/pk/asn1/x509/x509_decode_public_key_from_certificate.o src/pk/asn1/x509/x509_decode_spki.o \
 src/pk/asn1/x509/x509_decode_subject_public_key_info.o \
-src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o \
-src/pk/dh/dh_export.o src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o \
-src/pk/dh/dh_import.o src/pk/dh/dh_import_pkcs8.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o \
+src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/asn1/x509/x509_get_pka.o \
+src/pk/asn1/x509/x509_import_spki.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o src/pk/dh/dh_export.o \
+src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o src/pk/dh/dh_import.o \
+src/pk/dh/dh_import_pkcs8.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o \
 src/pk/dh/dh_shared_secret.o src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o \
 src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_generate_key.o \
 src/pk/dsa/dsa_generate_pqg.o src/pk/dsa/dsa_import.o src/pk/dsa/dsa_import_pkcs8.o \

+ 4 - 3
makefile.msvc

@@ -169,9 +169,10 @@ src/pk/asn1/oid/pk_get.obj src/pk/asn1/oid/pk_oid_cmp.obj src/pk/asn1/oid/pk_oid
 src/pk/asn1/pkcs8/pkcs8_decode_flexi.obj src/pk/asn1/pkcs8/pkcs8_get.obj \
 src/pk/asn1/x509/x509_decode_public_key_from_certificate.obj src/pk/asn1/x509/x509_decode_spki.obj \
 src/pk/asn1/x509/x509_decode_subject_public_key_info.obj \
-src/pk/asn1/x509/x509_encode_subject_public_key_info.obj src/pk/dh/dh.obj src/pk/dh/dh_check_pubkey.obj \
-src/pk/dh/dh_export.obj src/pk/dh/dh_export_key.obj src/pk/dh/dh_free.obj src/pk/dh/dh_generate_key.obj \
-src/pk/dh/dh_import.obj src/pk/dh/dh_import_pkcs8.obj src/pk/dh/dh_set.obj src/pk/dh/dh_set_pg_dhparam.obj \
+src/pk/asn1/x509/x509_encode_subject_public_key_info.obj src/pk/asn1/x509/x509_get_pka.obj \
+src/pk/asn1/x509/x509_import_spki.obj src/pk/dh/dh.obj src/pk/dh/dh_check_pubkey.obj src/pk/dh/dh_export.obj \
+src/pk/dh/dh_export_key.obj src/pk/dh/dh_free.obj src/pk/dh/dh_generate_key.obj src/pk/dh/dh_import.obj \
+src/pk/dh/dh_import_pkcs8.obj src/pk/dh/dh_set.obj src/pk/dh/dh_set_pg_dhparam.obj \
 src/pk/dh/dh_shared_secret.obj src/pk/dsa/dsa_decrypt_key.obj src/pk/dsa/dsa_encrypt_key.obj \
 src/pk/dsa/dsa_export.obj src/pk/dsa/dsa_free.obj src/pk/dsa/dsa_generate_key.obj \
 src/pk/dsa/dsa_generate_pqg.obj src/pk/dsa/dsa_import.obj src/pk/dsa/dsa_import_pkcs8.obj \

+ 4 - 3
makefile.unix

@@ -190,9 +190,10 @@ src/pk/asn1/oid/pk_get.o src/pk/asn1/oid/pk_oid_cmp.o src/pk/asn1/oid/pk_oid_str
 src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/pkcs8/pkcs8_get.o \
 src/pk/asn1/x509/x509_decode_public_key_from_certificate.o src/pk/asn1/x509/x509_decode_spki.o \
 src/pk/asn1/x509/x509_decode_subject_public_key_info.o \
-src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o \
-src/pk/dh/dh_export.o src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o \
-src/pk/dh/dh_import.o src/pk/dh/dh_import_pkcs8.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o \
+src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/asn1/x509/x509_get_pka.o \
+src/pk/asn1/x509/x509_import_spki.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o src/pk/dh/dh_export.o \
+src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o src/pk/dh/dh_import.o \
+src/pk/dh/dh_import_pkcs8.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o \
 src/pk/dh/dh_shared_secret.o src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o \
 src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_generate_key.o \
 src/pk/dsa/dsa_generate_pqg.o src/pk/dsa/dsa_import.o src/pk/dsa/dsa_import_pkcs8.o \

+ 4 - 3
makefile_include.mk

@@ -361,9 +361,10 @@ src/pk/asn1/oid/pk_get.o src/pk/asn1/oid/pk_oid_cmp.o src/pk/asn1/oid/pk_oid_str
 src/pk/asn1/pkcs8/pkcs8_decode_flexi.o src/pk/asn1/pkcs8/pkcs8_get.o \
 src/pk/asn1/x509/x509_decode_public_key_from_certificate.o src/pk/asn1/x509/x509_decode_spki.o \
 src/pk/asn1/x509/x509_decode_subject_public_key_info.o \
-src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o \
-src/pk/dh/dh_export.o src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o \
-src/pk/dh/dh_import.o src/pk/dh/dh_import_pkcs8.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o \
+src/pk/asn1/x509/x509_encode_subject_public_key_info.o src/pk/asn1/x509/x509_get_pka.o \
+src/pk/asn1/x509/x509_import_spki.o src/pk/dh/dh.o src/pk/dh/dh_check_pubkey.o src/pk/dh/dh_export.o \
+src/pk/dh/dh_export_key.o src/pk/dh/dh_free.o src/pk/dh/dh_generate_key.o src/pk/dh/dh_import.o \
+src/pk/dh/dh_import_pkcs8.o src/pk/dh/dh_set.o src/pk/dh/dh_set_pg_dhparam.o \
 src/pk/dh/dh_shared_secret.o src/pk/dsa/dsa_decrypt_key.o src/pk/dsa/dsa_encrypt_key.o \
 src/pk/dsa/dsa_export.o src/pk/dsa/dsa_free.o src/pk/dsa/dsa_generate_key.o \
 src/pk/dsa/dsa_generate_pqg.o src/pk/dsa/dsa_import.o src/pk/dsa/dsa_import_pkcs8.o \

+ 2 - 0
sources.cmake

@@ -373,6 +373,8 @@ src/pk/asn1/x509/x509_decode_public_key_from_certificate.c
 src/pk/asn1/x509/x509_decode_spki.c
 src/pk/asn1/x509/x509_decode_subject_public_key_info.c
 src/pk/asn1/x509/x509_encode_subject_public_key_info.c
+src/pk/asn1/x509/x509_get_pka.c
+src/pk/asn1/x509/x509_import_spki.c
 src/pk/dh/dh.c
 src/pk/dh/dh_check_pubkey.c
 src/pk/dh/dh_export.c

+ 47 - 11
src/headers/tomcrypt_private.h

@@ -352,19 +352,40 @@ struct bufp {
 };
 
 #define SET_BUFP(n, d, l) n.start = (char*)d, n.work = (char*)d, n.end = (char*)d + l + 1
+#define UPDATE_BUFP(n, d, w, l) n.start = (char*)d, n.work = (char*)d + w, n.end = (char*)d + l + 1
 
-struct get_char {
+struct get_char;
+struct get_char_api {
    int (*get)(struct get_char*);
+};
+
+struct get_char {
+   struct get_char_api api;
    union {
 #ifndef LTC_NO_FILE
-      FILE *f;
+      struct {
+         FILE *f;
+      } f;
 #endif /* LTC_NO_FILE */
       struct bufp buf;
    } data;
    struct str unget_buf;
    char unget_buf_[LTC_PEM_DECODE_BUFSZ];
    int prev_get;
+   unsigned long total_read;
 };
+
+#define pem_get_char_init(b, l)   { \
+   .api = get_char_buffer_api, \
+   SET_BUFP(.data.buf, (b), (l)), \
+   .total_read = 0, \
+}
+
+#define pem_get_char_init_filehandle(fi)    { \
+   .api = get_char_filehandle_api, \
+   .data.f.f = (fi), \
+   .total_read = 0, \
+}
 #endif
 
 /* others */
@@ -387,10 +408,10 @@ int pem_decrypt(unsigned char *data, unsigned long *datalen,
                 const struct blockcipher_info *info,
                 enum padding_type padding);
 #ifndef LTC_NO_FILE
-int pem_get_char_from_file(struct get_char *g);
+extern const struct get_char_api get_char_filehandle_api;
 #endif /* LTC_NO_FILE */
-int pem_get_char_from_buf(struct get_char *g);
-int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, struct get_char *g);
+extern const struct get_char_api get_char_buffer_api;
+int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g);
 #endif
 
 /* tomcrypt_pk.h */
@@ -651,17 +672,29 @@ int der_printable_value_decode(int v);
 
 unsigned long der_utf8_charsize(const wchar_t c);
 
-typedef struct {
+typedef int (*der_flexi_handler)(const ltc_asn1_list*, void*);
+
+typedef struct der_flexi_check {
    ltc_asn1_type t;
+   int optional;
    ltc_asn1_list **pp;
+   der_flexi_handler handler;
+   void *userdata;
 } der_flexi_check;
 
-#define LTC_SET_DER_FLEXI_CHECK(list, index, Type, P)    \
-   do {                                         \
-      int LTC_SDFC_temp##__LINE__ = (index);   \
-      list[LTC_SDFC_temp##__LINE__].t = Type;  \
-      list[LTC_SDFC_temp##__LINE__].pp = P;    \
+#define LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, P, Opt, Hndl, Udata)    \
+   do {                                                                 \
+      int LTC_SDFC_temp##__LINE__ = (index);                            \
+      list[LTC_SDFC_temp##__LINE__].t = Type;                           \
+      list[LTC_SDFC_temp##__LINE__].pp = P;                             \
+      list[LTC_SDFC_temp##__LINE__].optional = Opt;                     \
+      list[LTC_SDFC_temp##__LINE__].handler = (der_flexi_handler)Hndl;  \
+      list[LTC_SDFC_temp##__LINE__].userdata = Udata;                   \
    } while (0)
+#define LTC_SET_DER_FLEXI_CHECK(list, index, Type, P) LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, P, 0, NULL, NULL)
+#define LTC_SET_DER_FLEXI_CHECK_OPT(list, index, Type, P) LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, P, 1, NULL, NULL)
+#define LTC_SET_DER_FLEXI_HANDLER(list, index, Type, Hndl, Udata) LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, NULL, 0, Hndl, Udata)
+#define LTC_SET_DER_FLEXI_HANDLER_OPT(list, index, Type, Hndl, Udata) LTC_PRIV_SET_DER_FLEXI_CHECK(list, index, Type, NULL, 1, Hndl, Udata)
 
 
 extern const ltc_asn1_type  der_asn1_tag_to_type_map[];
@@ -697,6 +730,9 @@ int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long i
         enum ltc_oid_id algorithm, void *public_key, unsigned long *public_key_len,
         ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len);
 
+int x509_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka);
+int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root);
+
 int pk_oid_cmp_with_asn1(const char *o1, const ltc_asn1_list *o2);
 
 #endif /* LTC_DER */

+ 7 - 7
src/misc/pem/pem.c

@@ -10,6 +10,13 @@
 #ifdef LTC_PEM
 
 const struct pem_header_id pem_std_headers[] = {
+   {
+     /* X.509 Certificates */
+     SET_CSTR(.start, "-----BEGIN CERTIFICATE-----"),
+     SET_CSTR(.end, "-----END CERTIFICATE-----"),
+     .has_more_headers = no,
+     .flags = pf_x509,
+   },
    {
      /* PKCS#8 encrypted */
      SET_CSTR(.start, "-----BEGIN ENCRYPTED PRIVATE KEY-----"),
@@ -24,13 +31,6 @@ const struct pem_header_id pem_std_headers[] = {
      .has_more_headers = no,
      .flags = pf_pkcs8,
    },
-   {
-     /* X.509 Certificates */
-     SET_CSTR(.start, "-----BEGIN CERTIFICATE-----"),
-     SET_CSTR(.end, "-----END CERTIFICATE-----"),
-     .has_more_headers = no,
-     .flags = pf_x509,
-   },
    {
      /* Regular (plain) public keys */
      SET_CSTR(.start, "-----BEGIN PUBLIC KEY-----"),

+ 34 - 107
src/misc/pem/pem_pkcs.c

@@ -41,120 +41,50 @@ static int s_decrypt_pem(unsigned char *asn1_cert, unsigned long *asn1_len, cons
    return err;
 }
 
-static int s_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka)
-{
-   der_flexi_check flexi_should[4];
-   ltc_asn1_list *seqid, *id;
-   enum ltc_oid_id oid_id;
-   int err;
-   unsigned long n = 0;
-   LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seqid);
-   LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL);
-   LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
-   if ((err = der_flexi_sequence_cmp(pub, flexi_should)) != CRYPT_OK) {
-      return err;
-   }
-   n = 0;
-   LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OBJECT_IDENTIFIER, &id);
-   LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
-   err = der_flexi_sequence_cmp(seqid, flexi_should);
-   if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
-      return err;
-   }
-   if ((err = pk_get_oid_from_asn1(id, &oid_id)) != CRYPT_OK) {
-      return err;
-   }
-   return pk_get_pka_id(oid_id, pka);
-}
+typedef int (*pkcs8_import_fn)(ltc_asn1_list *, ltc_asn1_list *, void*);
 
-typedef int (*import_fn)(const unsigned char *, unsigned long, void*);
-
-static const import_fn s_import_x509_fns[LTC_PKA_NUM] = {
+static const struct {
+   enum ltc_pka_id id;
+   pkcs8_import_fn fn;
+} s_import_pkcs8_map[LTC_OID_NUM] = {
+#ifdef LTC_MDH
+                                                [LTC_OID_DH] = { LTC_PKA_DH, (pkcs8_import_fn)dh_import_pkcs8_asn1 },
+#endif
+#ifdef LTC_MDSA
+                                                [LTC_OID_DSA] = { LTC_PKA_DSA, (pkcs8_import_fn)dsa_import_pkcs8_asn1 },
+#endif
 #ifdef LTC_MRSA
-                                                [LTC_PKA_RSA] = (import_fn)rsa_import_x509,
+                                                [LTC_OID_RSA] = { LTC_PKA_RSA, (pkcs8_import_fn)rsa_import_pkcs8_asn1 },
 #endif
 #ifdef LTC_MECC
-                                                [LTC_PKA_EC] = (import_fn)ecc_import_x509,
+                                                [LTC_OID_EC] = { LTC_PKA_EC, (pkcs8_import_fn)ecc_import_pkcs8_asn1 },
 #endif
 #ifdef LTC_CURVE25519
-                                                [LTC_PKA_X25519] = (import_fn)x25519_import_x509,
-                                                [LTC_PKA_ED25519] = (import_fn)ed25519_import_x509,
+                                                [LTC_OID_X25519] =  { LTC_PKA_X25519, (pkcs8_import_fn)x25519_import_pkcs8_asn1 },
+                                                [LTC_OID_ED25519] = { LTC_PKA_ED25519, (pkcs8_import_fn)ed25519_import_pkcs8_asn1 },
 #endif
 };
 
-static int s_import_x509(unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k)
-{
-   enum ltc_pka_id pka = LTC_PKA_UNDEF;
-   ltc_asn1_list *d, *spki;
-   int err;
-   if ((err = x509_decode_spki(asn1_cert, asn1_len, &d, &spki)) != CRYPT_OK) {
-      return err;
-   }
-   err = s_get_pka(spki, &pka);
-   der_free_sequence_flexi(d);
-   if (err != CRYPT_OK) {
-      return err;
-   }
-   if (pka < 0
-         || pka > LTC_ARRAY_SIZE(s_import_x509_fns)
-         || s_import_x509_fns[pka] == NULL) {
-      return CRYPT_PK_INVALID_TYPE;
-   }
-   if ((err = s_import_x509_fns[pka](asn1_cert, asn1_len, &k->u)) == CRYPT_OK) {
-      k->id = pka;
-   }
-   return err;
-}
-
 static int s_import_pkcs8(unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, const password_ctx *pw_ctx)
 {
    int err;
-   enum ltc_oid_id pka;
+   enum ltc_oid_id oid_id;
    ltc_asn1_list *alg_id, *priv_key;
    ltc_asn1_list *p8_asn1 = NULL;
    if ((err = pkcs8_decode_flexi(asn1_cert, asn1_len, pw_ctx, &p8_asn1)) != CRYPT_OK) {
       goto cleanup;
    }
-   if ((err = pkcs8_get_children(p8_asn1, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
+   if ((err = pkcs8_get_children(p8_asn1, &oid_id, &alg_id, &priv_key)) != CRYPT_OK) {
       goto cleanup;
    }
-   switch (pka) {
-#ifdef LTC_MDH
-      case LTC_OID_DH:
-         err = dh_import_pkcs8_asn1(alg_id, priv_key, &k->u.dh);
-         k->id = LTC_PKA_DH;
-         break;
-#endif
-#ifdef LTC_MDSA
-      case LTC_OID_DSA:
-         err = dsa_import_pkcs8_asn1(alg_id, priv_key, &k->u.dsa);
-         k->id = LTC_PKA_DSA;
-         break;
-#endif
-#ifdef LTC_MRSA
-      case LTC_OID_RSA:
-         err = rsa_import_pkcs8_asn1(alg_id, priv_key, &k->u.rsa);
-         k->id = LTC_PKA_RSA;
-         break;
-#endif
-#ifdef LTC_MECC
-      case LTC_OID_EC:
-         err = ecc_import_pkcs8_asn1(alg_id, priv_key, &k->u.ecc);
-         k->id = LTC_PKA_EC;
-         break;
-#endif
-#ifdef LTC_CURVE25519
-      case LTC_OID_X25519:
-         err = x25519_import_pkcs8_asn1(alg_id, priv_key, &k->u.x25519);
-         k->id = LTC_PKA_X25519;
-         break;
-      case LTC_OID_ED25519:
-         err = ed25519_import_pkcs8_asn1(alg_id, priv_key, &k->u.ed25519);
-         k->id = LTC_PKA_ED25519;
-         break;
-#endif
-      default:
-         err = CRYPT_PK_INVALID_TYPE;
+   if (oid_id < 0
+         || oid_id > LTC_ARRAY_SIZE(s_import_pkcs8_map)
+         || s_import_pkcs8_map[oid_id].fn == NULL) {
+      err = CRYPT_PK_INVALID_TYPE;
+      goto cleanup;
+   }
+   if ((err = s_import_pkcs8_map[oid_id].fn(alg_id, priv_key, &k->u)) == CRYPT_OK) {
+      k->id = s_import_pkcs8_map[oid_id].id;
    }
 
 cleanup:
@@ -171,11 +101,13 @@ static int s_extract_pka(unsigned char *asn1_cert, unsigned long asn1_len, enum
    if ((err = der_decode_sequence_flexi(asn1_cert, &asn1_len, &pub)) != CRYPT_OK) {
       return err;
    }
-   err = s_get_pka(pub, pka);
+   err = x509_get_pka(pub, pka);
    der_sequence_free(pub);
    return err;
 }
 
+typedef int (*import_fn)(const unsigned char *, unsigned long, void*);
+
 static const import_fn s_import_openssl_fns[LTC_PKA_NUM] = {
 #ifdef LTC_MRSA
                                                 [LTC_PKA_RSA] = (import_fn)rsa_import,
@@ -195,21 +127,16 @@ static const import_fn s_import_openssl_fns[LTC_PKA_NUM] = {
 static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
 {
    unsigned char *asn1_cert = NULL;
-   unsigned long w, asn1_len, n;
+   unsigned long w = 0, asn1_len, n;
    int err = CRYPT_ERROR;
    struct pem_headers hdr = { 0 };
    struct password pw = { 0 };
    enum ltc_pka_id pka;
    XMEMSET(k, 0, sizeof(*k));
-   w = LTC_PEM_READ_BUFSIZE * 2;
-retry:
-   asn1_cert = XREALLOC(asn1_cert, w);
    for (n = 0; n < pem_std_headers_num; ++n) {
       hdr.id = &pem_std_headers[n];
-      err = pem_read(asn1_cert, &w, &hdr, g);
-      if (err == CRYPT_BUFFER_OVERFLOW) {
-         goto retry;
-      } else if (err == CRYPT_OK) {
+      err = pem_read((void**)&asn1_cert, &w, &hdr, g);
+      if (err == CRYPT_OK) {
          break;
       } else if (err != CRYPT_UNKNOWN_PEM) {
          goto cleanup;
@@ -224,7 +151,7 @@ retry:
       err = s_import_pkcs8(asn1_cert, asn1_len, k, pw_ctx);
       goto cleanup;
    } else if (hdr.id->flags == pf_x509) {
-      err = s_import_x509(asn1_cert, asn1_len, k);
+      err = x509_import_spki(asn1_cert, asn1_len, k, NULL);
       goto cleanup;
    } else if ((hdr.id->flags & pf_public) && hdr.id->pka == LTC_PKA_UNDEF) {
       if ((err = s_extract_pka(asn1_cert, asn1_len, &pka)) != CRYPT_OK) {
@@ -272,7 +199,7 @@ int pem_decode_pkcs_filehandle(FILE *f, ltc_pka_key *k, const password_ctx *pw_c
    LTC_ARGCHK(f != NULL);
    LTC_ARGCHK(k != NULL);
    {
-      struct get_char g = { .get = pem_get_char_from_file, .data.f = f };
+      struct get_char g = pem_get_char_init_filehandle(f);
       return s_decode(&g, k, pw_ctx);
    }
 }
@@ -284,7 +211,7 @@ int pem_decode_pkcs(const void *buf, unsigned long len, ltc_pka_key *k, const pa
    LTC_ARGCHK(len != 0);
    LTC_ARGCHK(k != NULL);
    {
-      struct get_char g = { .get = pem_get_char_from_buf, SET_BUFP(.data.buf, buf, len) };
+      struct get_char g = pem_get_char_init(buf, len);
       return s_decode(&g, k, pw_ctx);
    }
 }

+ 102 - 54
src/misc/pem/pem_read.c

@@ -17,14 +17,76 @@ extern const struct str pem_dek_info_start;
 extern const struct blockcipher_info pem_dek_infos[];
 extern const unsigned long pem_dek_infos_num;
 
+static LTC_INLINE unsigned long s_bufp_alloc_len(struct bufp *buf)
+{
+   if (buf->start == NULL || buf->end == NULL)
+      return 0;
+   return buf->end - buf->start - 1;
+}
+
+static LTC_INLINE unsigned long s_bufp_used_len(struct bufp *buf)
+{
+   if (buf->start == NULL || buf->end == NULL)
+      return 0;
+   return buf->work - buf->start;
+}
+
+static LTC_INLINE int s_bufp_grow(struct bufp *buf)
+{
+   int err = CRYPT_OK;
+   void *ret;
+   unsigned long alloc_len = s_bufp_alloc_len(buf), realloc_len;
+   unsigned long work_offset = s_bufp_used_len(buf);
+   if (alloc_len == 0)
+      realloc_len = LTC_PEM_READ_BUFSIZE;
+   else
+      realloc_len = alloc_len * 2;
+   if (realloc_len < alloc_len)
+      return CRYPT_OVERFLOW;
+   ret = XREALLOC(buf->start, realloc_len);
+   if (ret == NULL) {
+      err = CRYPT_MEM;
+   } else {
+      UPDATE_BUFP((*buf), ret, work_offset, realloc_len);
+   }
+   return err;
+}
+
+static LTC_INLINE int s_bufp_fits(struct bufp *buf, unsigned long to_write)
+{
+   char *d = buf->work;
+   char *e = buf->end;
+   char *w = d + to_write;
+   if (d == NULL || w < d || w > e)
+      return 0;
+   return 1;
+}
+
+static LTC_INLINE int s_bufp_add(struct bufp *buf, const void *src, unsigned long len)
+{
+   int err;
+   if (!s_bufp_fits(buf, len)) {
+      if ((err = s_bufp_grow(buf)) != CRYPT_OK) {
+         return err;
+      }
+   }
+   XMEMCPY(buf->work, src, len);
+   buf->work += len;
+   return CRYPT_OK;
+}
+
 #ifndef LTC_NO_FILE
-int pem_get_char_from_file(struct get_char *g)
+static int s_pem_get_char_from_file(struct get_char *g)
 {
-   return getc(g->data.f);
+   return getc(g->data.f.f);
 }
+
+const struct get_char_api get_char_filehandle_api = {
+                                                     .get = s_pem_get_char_from_file,
+};
 #endif /* LTC_NO_FILE */
 
-int pem_get_char_from_buf(struct get_char *g)
+static int s_pem_get_char_from_buf(struct get_char *g)
 {
    int ret;
    if (g->data.buf.work == g->data.buf.end) {
@@ -35,6 +97,10 @@ int pem_get_char_from_buf(struct get_char *g)
    return ret;
 }
 
+const struct get_char_api get_char_buffer_api = {
+                                                     .get = s_pem_get_char_from_buf,
+};
+
 static void s_unget_line(char *buf, unsigned long buflen, struct get_char *g)
 {
    if (buflen > sizeof(g->unget_buf_))
@@ -81,7 +147,7 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g,
    while(blen < *buflen || search_for_start) {
       wr = blen < *buflen ? blen : *buflen - 1;
       c_ = g->prev_get;
-      g->prev_get = g->get(g);
+      g->prev_get = g->api.get(g);
       if (g->prev_get == '\n') {
          buf[wr] = '\0';
          if (c_ == '\r') {
@@ -89,6 +155,7 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g,
          }
          s_tts(buf, &wr);
          *buflen = wr;
+         g->total_read++;
          return buf;
       }
       if (g->prev_get == -1 || g->prev_get == '\0') {
@@ -99,30 +166,21 @@ static char* s_get_line_i(char *buf, unsigned long *buflen, struct get_char *g,
       }
       buf[wr] = g->prev_get;
       blen++;
+      g->total_read++;
    }
    return NULL;
 }
 
-LTC_INLINE static char* s_get_first_line(char *buf, unsigned long *buflen, struct get_char *g)
+static LTC_INLINE char* s_get_first_line(char *buf, unsigned long *buflen, struct get_char *g)
 {
    return s_get_line_i(buf, buflen, g, 1);
 }
 
-LTC_INLINE static char* s_get_line(char *buf, unsigned long *buflen, struct get_char *g)
+static LTC_INLINE char* s_get_line(char *buf, unsigned long *buflen, struct get_char *g)
 {
    return s_get_line_i(buf, buflen, g, 0);
 }
 
-static LTC_INLINE int s_fits_buf(void *dest, unsigned long to_write, void *end)
-{
-   unsigned char *d = dest;
-   unsigned char *e = end;
-   unsigned char *w = d + to_write;
-   if (w < d || w > e)
-      return 0;
-   return 1;
-}
-
 static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g)
 {
    char buf[LTC_PEM_DECODE_BUFSZ], *alg_start;
@@ -190,31 +248,29 @@ static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g)
    return CRYPT_OK;
 }
 
-int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr, struct get_char *g)
+int pem_read(void **dest, unsigned long *len, struct pem_headers *hdr, struct get_char *g)
 {
-   char buf[LTC_PEM_DECODE_BUFSZ];
-   char *wpem = asn1_cert;
-   char *end = wpem + *asn1_len;
+   char line[LTC_PEM_DECODE_BUFSZ];
+   struct bufp b_ = {0}, *b = &b_;
    const char pem_start[] = "----";
-   unsigned long slen, linelen;
+   unsigned long slen;
    int err, hdr_ok = 0;
-   int would_overflow = 0;
    unsigned char empty_lines = 0;
 
    g->prev_get = 0;
    do {
-      linelen = sizeof(buf);
-      if (s_get_first_line(buf, &linelen, g) == NULL) {
+      slen = sizeof(line);
+      if (s_get_first_line(line, &slen, g) == NULL) {
          if (g->prev_get == -1)
             return CRYPT_NOP;
          else
             return CRYPT_INVALID_PACKET;
       }
-      if (linelen < sizeof(pem_start) - 1)
+      if (slen < sizeof(pem_start) - 1)
          continue;
-   } while(XMEMCMP(buf, pem_start, sizeof(pem_start) - 1) != 0);
-   if (hdr->id->start.len != linelen || XMEMCMP(buf, hdr->id->start.p, hdr->id->start.len)) {
-      s_unget_line(buf, linelen, g);
+   } while(XMEMCMP(line, pem_start, sizeof(pem_start) - 1) != 0);
+   if (hdr->id->start.len != slen || XMEMCMP(line, hdr->id->start.p, hdr->id->start.len)) {
+      s_unget_line(line, slen, g);
       return CRYPT_UNKNOWN_PEM;
    }
 
@@ -223,9 +279,9 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
       return err;
 
    /* Read the base64 encoded part of the PEM */
-   slen = sizeof(buf);
-   while (s_get_line(buf, &slen, g)) {
-      if (slen == hdr->id->end.len && !XMEMCMP(buf, hdr->id->end.p, slen)) {
+   slen = sizeof(line);
+   while (s_get_line(line, &slen, g)) {
+      if (slen == hdr->id->end.len && !XMEMCMP(line, hdr->id->end.p, slen)) {
          hdr_ok = 1;
          break;
       }
@@ -234,34 +290,26 @@ int pem_read(void *asn1_cert, unsigned long *asn1_len, struct pem_headers *hdr,
             break;
          empty_lines++;
       }
-      if (!would_overflow && s_fits_buf(wpem, slen, end)) {
-         XMEMCPY(wpem, buf, slen);
-      } else {
-         would_overflow = 1;
+      if ((err = s_bufp_add(b, line, slen)) != CRYPT_OK) {
+         goto error_out;
       }
-      wpem += slen;
-      slen = sizeof(buf);
+      slen = sizeof(line);
    }
-   if (!hdr_ok)
-      return CRYPT_INVALID_PACKET;
-
-   if (would_overflow || !s_fits_buf(wpem, 1, end)) {
-      /* NUL termination */
-      wpem++;
-      /* prevent a wrap-around */
-      if (wpem < (char*)asn1_cert)
-         return CRYPT_OVERFLOW;
-      *asn1_len = wpem - (char*)asn1_cert;
-      return CRYPT_BUFFER_OVERFLOW;
+   if (!hdr_ok) {
+      err = CRYPT_INVALID_PACKET;
+   } else {
+      slen = s_bufp_alloc_len(b);
+      err = base64_strict_decode(b->start, s_bufp_used_len(b), (void*)b->start, &slen);
    }
+   if (err == CRYPT_OK) {
+      *dest = b->start;
+      *len = slen;
 
-   *asn1_len = wpem - (char*)asn1_cert;
-   *wpem++ = '\0';
-
-   if ((err = base64_strict_decode(asn1_cert, *asn1_len, asn1_cert, asn1_len)) != CRYPT_OK) {
-      return err;
+   } else {
+error_out:
+      XFREE(b->start);
    }
-   return CRYPT_OK;
+   return err;
 }
 
 #endif /* LTC_PEM */

+ 8 - 11
src/misc/pem/pem_ssh.c

@@ -712,20 +712,15 @@ static const unsigned long pem_openssh_num = LTC_ARRAY_SIZE(pem_openssh);
 static int s_decode_openssh(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
 {
    unsigned char *pem = NULL, *p, *privkey = NULL, *tag;
-   unsigned long n, w, l, privkey_len, taglen;
+   unsigned long n, w = 0, l, privkey_len, taglen;
    int err;
    struct pem_headers hdr;
    struct kdf_options opts = { 0 };
    XMEMSET(k, 0, sizeof(*k));
-   w = LTC_PEM_READ_BUFSIZE * 2;
-retry:
-   pem = XREALLOC(pem, w);
    for (n = 0; n < pem_openssh_num; ++n) {
       hdr.id = &pem_openssh[n];
-      err = pem_read(pem, &w, &hdr, g);
-      if (err == CRYPT_BUFFER_OVERFLOW) {
-         goto retry;
-      } else if (err == CRYPT_OK) {
+      err = pem_read((void**)&pem, &w, &hdr, g);
+      if (err == CRYPT_OK) {
          break;
       } else if (err != CRYPT_UNKNOWN_PEM) {
          goto cleanup;
@@ -791,7 +786,9 @@ cleanup:
       zeromem(privkey, privkey_len);
       XFREE(privkey);
    }
-   XFREE(pem);
+   if (pem) {
+      XFREE(pem);
+   }
    return err;
 }
 
@@ -801,7 +798,7 @@ int pem_decode_openssh_filehandle(FILE *f, ltc_pka_key *k, const password_ctx *p
    LTC_ARGCHK(f != NULL);
    LTC_ARGCHK(k != NULL);
    {
-      struct get_char g = { .get = pem_get_char_from_file, .data.f = f };
+      struct get_char g = pem_get_char_init_filehandle(f);
       return s_decode_openssh(&g, k, pw_ctx);
    }
 }
@@ -841,7 +838,7 @@ int pem_decode_openssh(const void *buf, unsigned long len, ltc_pka_key *k, const
    LTC_ARGCHK(len != 0);
    LTC_ARGCHK(k != NULL);
    {
-      struct get_char g = { .get = pem_get_char_from_buf, SET_BUFP(.data.buf, buf, len) };
+      struct get_char g = pem_get_char_init(buf, len);
       return s_decode_openssh(&g, k, pw_ctx);
    }
 }

+ 10 - 1
src/pk/asn1/der/sequence/der_flexi_sequence_cmp.c

@@ -24,11 +24,20 @@ int der_flexi_sequence_cmp(const ltc_asn1_list *flexi, der_flexi_check *check)
       return CRYPT_INVALID_PACKET;
    }
    cur = flexi->child;
-   while(check->t != LTC_ASN1_EOL) {
+   while(check->t != LTC_ASN1_EOL && cur) {
       if (!LTC_ASN1_IS_TYPE(cur, check->t)) {
+         if (check->optional) {
+            check++;
+            continue;
+         }
          return CRYPT_INVALID_PACKET;
       }
       if (check->pp != NULL) *check->pp = cur;
+      else if (check->handler) {
+         int err = check->handler(cur, check->userdata);
+         if (err != CRYPT_OK)
+            return err;
+      }
       cur = cur->next;
       check++;
    }

+ 38 - 0
src/pk/asn1/x509/x509_get_pka.c

@@ -0,0 +1,38 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+  @file x509_get_pka.c
+  Extract the PKA from an X.509 cert, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+int x509_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka)
+{
+   der_flexi_check flexi_should[4];
+   ltc_asn1_list *seqid, *id = NULL;
+   enum ltc_oid_id oid_id;
+   int err;
+   unsigned long n = 0;
+   LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seqid);
+   LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL);
+   LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
+   if ((err = der_flexi_sequence_cmp(pub, flexi_should)) != CRYPT_OK) {
+      return err;
+   }
+   n = 0;
+   LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OBJECT_IDENTIFIER, &id);
+   LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
+   err = der_flexi_sequence_cmp(seqid, flexi_should);
+   if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
+      return err;
+   }
+   if ((err = pk_get_oid_from_asn1(id, &oid_id)) != CRYPT_OK) {
+      return err;
+   }
+   return pk_get_pka_id(oid_id, pka);
+}
+
+#endif /* LTC_DER */

+ 59 - 0
src/pk/asn1/x509/x509_import_spki.c

@@ -0,0 +1,59 @@
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis */
+/* SPDX-License-Identifier: Unlicense */
+#include "tomcrypt_private.h"
+
+/**
+  @file x509_import_spki.c
+  Import the SubjectPublicKeyInfo of an X.509 cert, Steffen Jaeckel
+*/
+
+#ifdef LTC_DER
+
+typedef int (*import_fn)(const unsigned char *, unsigned long, void*);
+
+static const import_fn s_import_x509_fns[LTC_PKA_NUM] = {
+#ifdef LTC_MRSA
+                                                [LTC_PKA_RSA] = (import_fn)rsa_import_x509,
+#endif
+#ifdef LTC_MDSA
+                                                [LTC_PKA_DSA] = (import_fn)dsa_import,
+#endif
+#ifdef LTC_MECC
+                                                [LTC_PKA_EC] = (import_fn)ecc_import_x509,
+#endif
+#ifdef LTC_CURVE25519
+                                                [LTC_PKA_X25519] = (import_fn)x25519_import_x509,
+                                                [LTC_PKA_ED25519] = (import_fn)ed25519_import_x509,
+#endif
+};
+
+int x509_import_spki(const unsigned char *asn1_cert, unsigned long asn1_len, ltc_pka_key *k, ltc_asn1_list **root)
+{
+   enum ltc_pka_id pka = LTC_PKA_UNDEF;
+   ltc_asn1_list *d, *spki;
+   int err;
+   if ((err = x509_decode_spki(asn1_cert, asn1_len, &d, &spki)) != CRYPT_OK) {
+      return err;
+   }
+   if ((err = x509_get_pka(spki, &pka)) != CRYPT_OK) {
+      goto err_out;
+   }
+   if (pka < 0
+         || pka > LTC_ARRAY_SIZE(s_import_x509_fns)
+         || s_import_x509_fns[pka] == NULL) {
+      err = CRYPT_PK_INVALID_TYPE;
+      goto err_out;
+   }
+   if ((err = s_import_x509_fns[pka](asn1_cert, asn1_len, &k->u)) == CRYPT_OK) {
+      k->id = pka;
+   }
+err_out:
+   if (err == CRYPT_OK && root) {
+      *root = d;
+      d = NULL;
+   }
+   der_free_sequence_flexi(d);
+   return err;
+}
+
+#endif /* LTC_DER */

+ 71 - 30
src/pk/dsa/dsa_import.c

@@ -28,6 +28,69 @@ int dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key)
    return err;
 }
 
+static int s_dsa_import_y(const unsigned char *in, unsigned long inlen, dsa_key *key)
+{
+   return der_decode_integer(in, inlen, key->y);
+}
+
+LTC_INLINE static int s_dsa_set_params(dsa_key *key, ltc_asn1_list *params)
+{
+   LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, key->p, 1UL);
+   LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, key->q, 1UL);
+   LTC_SET_ASN1(params, 2, LTC_ASN1_INTEGER, key->g, 1UL);
+   return 3;
+}
+
+static int s_dsa_import_spki(const unsigned char *in, unsigned long inlen, dsa_key *key)
+{
+   int err;
+   unsigned char* tmpbuf = NULL;
+   ltc_asn1_list params[3];
+   unsigned long tmpbuf_len = inlen, len;
+
+   len = s_dsa_set_params(key, params);
+
+   tmpbuf = XCALLOC(1, tmpbuf_len);
+   if (tmpbuf == NULL) {
+      return CRYPT_MEM;
+   }
+
+   err = x509_decode_subject_public_key_info(in, inlen,
+                                             LTC_OID_DSA,       tmpbuf, &tmpbuf_len,
+                                             LTC_ASN1_SEQUENCE, params, &len);
+   if (err != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   if ((err = s_dsa_import_y(tmpbuf, tmpbuf_len, key)) != CRYPT_OK) {
+      goto LBL_ERR;
+   }
+
+   key->type = PK_PUBLIC;
+LBL_ERR:
+   XFREE(tmpbuf);
+   return err;
+}
+
+static int s_dsa_import_x509(const unsigned char *in, unsigned long inlen, dsa_key *key)
+{
+   int err;
+   ltc_asn1_list params[3];
+   unsigned long len;
+
+   len = s_dsa_set_params(key, params);
+
+   if ((err = x509_decode_public_key_from_certificate(in, inlen,
+                                                      LTC_OID_DSA,
+                                                      LTC_ASN1_SEQUENCE, params, &len,
+                                                      (public_key_decode_cb)s_dsa_import_y, key)) == CRYPT_OK) {
+      key->type = PK_PUBLIC;
+      return CRYPT_OK;
+   }
+
+   return err;
+}
+
 /**
    Import a DSA key
    @param in       The binary packet to import from
@@ -38,7 +101,6 @@ int dsa_import_pkcs1(const unsigned char *in, unsigned long inlen, dsa_key *key)
 int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key)
 {
    int           err, stat;
-   unsigned char* tmpbuf = NULL;
    unsigned char flags[1];
 
    LTC_ARGCHK(in  != NULL);
@@ -86,35 +148,14 @@ int dsa_import(const unsigned char *in, unsigned long inlen, dsa_key *key)
        }
    }
 
-   if (dsa_import_pkcs1(in, inlen, key) != CRYPT_OK) {
-      ltc_asn1_list params[3];
-      unsigned long tmpbuf_len = inlen, len;
-
-      LTC_SET_ASN1(params, 0, LTC_ASN1_INTEGER, key->p, 1UL);
-      LTC_SET_ASN1(params, 1, LTC_ASN1_INTEGER, key->q, 1UL);
-      LTC_SET_ASN1(params, 2, LTC_ASN1_INTEGER, key->g, 1UL);
-      len = 3;
-
-      tmpbuf = XCALLOC(1, tmpbuf_len);
-      if (tmpbuf == NULL) {
-         return CRYPT_MEM;
-      }
-
-      err = x509_decode_subject_public_key_info(in, inlen,
-                                                LTC_OID_DSA,       tmpbuf, &tmpbuf_len,
-                                                LTC_ASN1_SEQUENCE, params, &len);
-      if (err != CRYPT_OK) {
-         XFREE(tmpbuf);
-         goto LBL_ERR;
-      }
-
-      if ((err = der_decode_integer(tmpbuf, tmpbuf_len, key->y)) != CRYPT_OK) {
-         XFREE(tmpbuf);
-         goto LBL_ERR;
-      }
-
-      key->type = PK_PUBLIC;
-      XFREE(tmpbuf);
+   if (dsa_import_pkcs1(in, inlen, key) == CRYPT_OK) {
+      goto LBL_OK;
+   }
+   if (s_dsa_import_spki(in, inlen, key) == CRYPT_OK) {
+      goto LBL_OK;
+   }
+   if ((err = s_dsa_import_x509(in, inlen, key)) != CRYPT_OK) {
+      goto LBL_ERR;
    }
 
 LBL_OK:

+ 1 - 2
tests/pkcs_1_eme_test.c

@@ -24,8 +24,7 @@ int pkcs_1_eme_test(void)
   for (i = 0; i < LTC_ARRAY_SIZE(testcases_eme); ++i) {
     testcase_t* t = &testcases_eme[i];
     rsa_key k, *key = &k;
-    DOX(ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ,
-                       &key->dP, &key->qP, &key->p, &key->q, NULL), t->name);
+    DOX(rsa_init(key), t->name);
 
     DOX(ltc_mp_read_unsigned_bin(key->e, t->rsa.e, t->rsa.e_l), t->name);
     DOX(ltc_mp_read_unsigned_bin(key->d, t->rsa.d, t->rsa.d_l), t->name);

+ 1 - 2
tests/pkcs_1_emsa_test.c

@@ -21,8 +21,7 @@ int pkcs_1_emsa_test(void)
   for (i = 0; i < LTC_ARRAY_SIZE(testcases_emsa); ++i) {
     testcase_t* t = &testcases_emsa[i];
     rsa_key k, *key = &k;
-    DOX(ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ,
-                       &key->dP, &key->qP, &key->p, &key->q, NULL), t->name);
+    DOX(rsa_init(key), t->name);
 
     DOX(ltc_mp_read_unsigned_bin(key->e, t->rsa.e, t->rsa.e_l), t->name);
     DOX(ltc_mp_read_unsigned_bin(key->d, t->rsa.d, t->rsa.d_l), t->name);

+ 1 - 2
tests/pkcs_1_oaep_test.c

@@ -24,8 +24,7 @@ int pkcs_1_oaep_test(void)
   for (i = 0; i < LTC_ARRAY_SIZE(testcases_oaep); ++i) {
     testcase_t* t = &testcases_oaep[i];
     rsa_key k, *key = &k;
-    DOX(ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ,
-                       &key->dP, &key->qP, &key->p, &key->q, NULL), t->name);
+    DOX(rsa_init(key), t->name);
 
     DOX(ltc_mp_read_unsigned_bin(key->e, t->rsa.e, t->rsa.e_l), t->name);
     DOX(ltc_mp_read_unsigned_bin(key->d, t->rsa.d, t->rsa.d_l), t->name);

+ 1 - 2
tests/pkcs_1_pss_test.c

@@ -24,8 +24,7 @@ int pkcs_1_pss_test(void)
   for (i = 0; i < LTC_ARRAY_SIZE(testcases_pss); ++i) {
     testcase_t* t = &testcases_pss[i];
     rsa_key k, *key = &k;
-    DOX(ltc_mp_init_multi(&key->e, &key->d, &key->N, &key->dQ,
-                       &key->dP, &key->qP, &key->p, &key->q, NULL), t->name);
+    DOX(rsa_init(key), t->name);
 
     DOX(ltc_mp_read_unsigned_bin(key->e, t->rsa.e, t->rsa.e_l), t->name);
     DOX(ltc_mp_read_unsigned_bin(key->d, t->rsa.d, t->rsa.d_l), t->name);