diff --git a/libtomcrypt_VS2008.vcproj b/libtomcrypt_VS2008.vcproj
index 66375779f..200dc670a 100644
--- a/libtomcrypt_VS2008.vcproj
+++ b/libtomcrypt_VS2008.vcproj
@@ -2281,6 +2281,14 @@
RelativePath="src\pk\asn1\x509\x509_encode_subject_public_key_info.c"
>
+
+
+
+
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 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
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);
}
}
diff --git a/src/misc/pem/pem_read.c b/src/misc/pem/pem_read.c
index abefff924..bbc61cb0d 100644
--- a/src/misc/pem/pem_read.c
+++ b/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 */
diff --git a/src/misc/pem/pem_ssh.c b/src/misc/pem/pem_ssh.c
index 77fa87be9..d4de0865a 100644
--- a/src/misc/pem/pem_ssh.c
+++ b/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 @@ static int s_decode_openssh(struct get_char *g, ltc_pka_key *k, const password_c
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);
}
}
diff --git a/src/pk/asn1/der/sequence/der_flexi_sequence_cmp.c b/src/pk/asn1/der/sequence/der_flexi_sequence_cmp.c
index 026eb504a..535483f59 100644
--- a/src/pk/asn1/der/sequence/der_flexi_sequence_cmp.c
+++ b/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++;
}
diff --git a/src/pk/asn1/x509/x509_get_pka.c b/src/pk/asn1/x509/x509_get_pka.c
new file mode 100644
index 000000000..23a12edd7
--- /dev/null
+++ b/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 */
diff --git a/src/pk/asn1/x509/x509_import_spki.c b/src/pk/asn1/x509/x509_import_spki.c
new file mode 100644
index 000000000..8b360852e
--- /dev/null
+++ b/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 */
diff --git a/src/pk/dsa/dsa_import.c b/src/pk/dsa/dsa_import.c
index d2c2d49ec..3db1afd32 100644
--- a/src/pk/dsa/dsa_import.c
+++ b/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:
diff --git a/tests/pkcs_1_eme_test.c b/tests/pkcs_1_eme_test.c
index ca540360b..9e818ace6 100644
--- a/tests/pkcs_1_eme_test.c
+++ b/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);
diff --git a/tests/pkcs_1_emsa_test.c b/tests/pkcs_1_emsa_test.c
index ba66f079a..43fb112ae 100644
--- a/tests/pkcs_1_emsa_test.c
+++ b/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);
diff --git a/tests/pkcs_1_oaep_test.c b/tests/pkcs_1_oaep_test.c
index 1cb6ca128..76157c2c0 100644
--- a/tests/pkcs_1_oaep_test.c
+++ b/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);
diff --git a/tests/pkcs_1_pss_test.c b/tests/pkcs_1_pss_test.c
index a62e53ff0..a86e473ac 100644
--- a/tests/pkcs_1_pss_test.c
+++ b/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);