Skip to content

Commit 8d19047

Browse files
committed
Add support for more PEM file types + some fixes
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
1 parent 7b5d85d commit 8d19047

20 files changed

+587
-217
lines changed

src/headers/tomcrypt_pk.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ enum ltc_pka_id {
3030
LTC_PKA_X25519,
3131
LTC_PKA_ED25519,
3232
LTC_PKA_DH,
33+
LTC_PKA_NUM
3334
};
3435

3536
enum public_key_type {

src/headers/tomcrypt_private.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,7 @@ enum pem_flags {
297297
pf_encrypted = 0x01u,
298298
pf_pkcs8 = 0x02u,
299299
pf_public = 0x04u,
300+
pf_x509 = 0x08u,
300301
pf_encrypted_pkcs8 = pf_encrypted | pf_pkcs8,
301302
};
302303

@@ -568,14 +569,15 @@ int x509_decode_public_key_from_certificate(const unsigned char *in, unsigned lo
568569
enum ltc_oid_id algorithm, ltc_asn1_type param_type,
569570
ltc_asn1_list* parameters, unsigned long *parameters_len,
570571
public_key_decode_cb callback, void *ctx);
572+
int x509_decode_spki(const unsigned char *in, unsigned long inlen, ltc_asn1_list **out, ltc_asn1_list **spki);
571573

572574
/* SUBJECT PUBLIC KEY INFO */
573575
int x509_encode_subject_public_key_info(unsigned char *out, unsigned long *outlen,
574-
unsigned int algorithm, const void* public_key, unsigned long public_key_len,
576+
enum ltc_oid_id algorithm, const void* public_key, unsigned long public_key_len,
575577
ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long parameters_len);
576578

577579
int x509_decode_subject_public_key_info(const unsigned char *in, unsigned long inlen,
578-
unsigned int algorithm, void* public_key, unsigned long* public_key_len,
580+
enum ltc_oid_id algorithm, void *public_key, unsigned long *public_key_len,
579581
ltc_asn1_type parameters_type, ltc_asn1_list* parameters, unsigned long *parameters_len);
580582

581583
int pk_oid_cmp_with_ulong(const char *o1, const unsigned long *o2, unsigned long o2size);

src/misc/pem/pem.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,27 @@ const struct pem_header_id pem_std_headers[] = {
2424
.has_more_headers = no,
2525
.flags = pf_pkcs8,
2626
},
27+
{
28+
/* X.509 Certificates */
29+
SET_CSTR(.start, "-----BEGIN CERTIFICATE-----"),
30+
SET_CSTR(.end, "-----END CERTIFICATE-----"),
31+
.has_more_headers = no,
32+
.flags = pf_x509,
33+
},
2734
{
2835
/* Regular (plain) public keys */
2936
SET_CSTR(.start, "-----BEGIN PUBLIC KEY-----"),
3037
SET_CSTR(.end, "-----END PUBLIC KEY-----"),
3138
.has_more_headers = no,
3239
.flags = pf_public,
3340
},
41+
{
42+
SET_CSTR(.start, "-----BEGIN RSA PUBLIC KEY-----"),
43+
SET_CSTR(.end, "-----END RSA PUBLIC KEY-----"),
44+
.has_more_headers = no,
45+
.pka = LTC_PKA_RSA,
46+
.flags = pf_public,
47+
},
3448
/* Regular plain or encrypted private keys */
3549
{
3650
SET_CSTR(.start, "-----BEGIN RSA PRIVATE KEY-----"),
@@ -55,6 +69,9 @@ const unsigned long pem_std_headers_num = sizeof(pem_std_headers)/sizeof(pem_std
5569

5670
/* Encrypted PEM files */
5771
const struct str pem_proc_type_encrypted = { SET_CSTR(, "Proc-Type: 4,ENCRYPTED") };
72+
#if defined(LTC_SSH)
73+
const struct str pem_ssh_comment = { SET_CSTR(, "Comment: ") };
74+
#endif
5875
const struct str pem_dek_info_start = { SET_CSTR(, "DEK-Info: ") };
5976
const struct blockcipher_info pem_dek_infos[] =
6077
{

src/misc/pem/pem_pkcs.c

Lines changed: 107 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,71 @@ static int s_decrypt_pem(unsigned char *pem, unsigned long *l, const struct pem_
4545
return err;
4646
}
4747

48+
static int s_get_pka(ltc_asn1_list *pub, enum ltc_pka_id *pka)
49+
{
50+
der_flexi_check flexi_should[4];
51+
ltc_asn1_list *seqid, *id;
52+
enum ltc_oid_id oid_id;
53+
int err;
54+
unsigned long n = 0;
55+
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seqid);
56+
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL);
57+
LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
58+
if ((err = der_flexi_sequence_cmp(pub, flexi_should)) != CRYPT_OK) {
59+
return err;
60+
}
61+
n = 0;
62+
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OBJECT_IDENTIFIER, &id);
63+
LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
64+
err = der_flexi_sequence_cmp(seqid, flexi_should);
65+
if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
66+
return err;
67+
}
68+
if ((err = pk_get_oid_from_asn1(id, &oid_id)) != CRYPT_OK) {
69+
return err;
70+
}
71+
return pk_get_pka_id(oid_id, pka);
72+
}
73+
74+
typedef int (*import_fn)(const unsigned char *, unsigned long, void*);
75+
76+
static import_fn s_import_x509_fns[LTC_PKA_NUM] = {
77+
#ifdef LTC_MRSA
78+
[LTC_PKA_RSA] = (import_fn)rsa_import_x509,
79+
#endif
80+
#ifdef LTC_MECC
81+
[LTC_PKA_EC] = (import_fn)ecc_import_x509,
82+
#endif
83+
#ifdef LTC_CURVE25519
84+
[LTC_PKA_X25519] = (import_fn)x25519_import_x509,
85+
[LTC_PKA_ED25519] = (import_fn)ed25519_import_x509,
86+
#endif
87+
};
88+
89+
static int s_import_x509(unsigned char *pem, unsigned long l, ltc_pka_key *k)
90+
{
91+
enum ltc_pka_id pka = LTC_PKA_UNDEF;
92+
ltc_asn1_list *d, *spki;
93+
int err;
94+
if ((err = x509_decode_spki(pem, l, &d, &spki)) != CRYPT_OK) {
95+
return err;
96+
}
97+
err = s_get_pka(spki, &pka);
98+
der_free_sequence_flexi(d);
99+
if (err != CRYPT_OK) {
100+
return err;
101+
}
102+
if (pka < 0
103+
|| pka > sizeof(s_import_x509_fns)/sizeof(s_import_x509_fns[0])
104+
|| s_import_x509_fns[pka] == NULL) {
105+
return CRYPT_PK_INVALID_TYPE;
106+
}
107+
if ((err = s_import_x509_fns[pka](pem, l, &k->u)) == CRYPT_OK) {
108+
k->id = pka;
109+
}
110+
return err;
111+
}
112+
48113
static int s_import_pkcs8(unsigned char *pem, unsigned long l, ltc_pka_key *k, const password_ctx *pw_ctx)
49114
{
50115
int err;
@@ -103,16 +168,41 @@ static int s_import_pkcs8(unsigned char *pem, unsigned long l, ltc_pka_key *k, c
103168
return err;
104169
}
105170

171+
int s_extract_pka(unsigned char *pem, unsigned long w, enum ltc_pka_id *pka)
172+
{
173+
ltc_asn1_list *pub;
174+
int err = CRYPT_ERROR;
175+
if ((err = der_decode_sequence_flexi(pem, &w, &pub)) != CRYPT_OK) {
176+
return err;
177+
}
178+
err = s_get_pka(pub, pka);
179+
der_sequence_free(pub);
180+
return err;
181+
}
182+
183+
static import_fn s_import_openssl_fns[LTC_PKA_NUM] = {
184+
#ifdef LTC_MRSA
185+
[LTC_PKA_RSA] = (import_fn)rsa_import,
186+
#endif
187+
#ifdef LTC_MDSA
188+
[LTC_PKA_DSA] = (import_fn)dsa_import,
189+
#endif
190+
#ifdef LTC_MECC
191+
[LTC_PKA_EC] = (import_fn)ecc_import_openssl,
192+
#endif
193+
#ifdef LTC_CURVE25519
194+
[LTC_PKA_X25519] = (import_fn)x25519_import,
195+
[LTC_PKA_ED25519] = (import_fn)ed25519_import,
196+
#endif
197+
};
198+
106199
static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
107200
{
108201
unsigned char *pem = NULL;
109202
unsigned long w, l, n;
110203
int err = CRYPT_ERROR;
111204
struct pem_headers hdr = { 0 };
112205
struct password pw;
113-
ltc_asn1_list *pub = NULL, *seqid, *id;
114-
der_flexi_check flexi_should[4];
115-
enum ltc_oid_id oid_id;
116206
enum ltc_pka_id pka;
117207
XMEMSET(k, 0, sizeof(*k));
118208
w = LTC_PEM_READ_BUFSIZE * 2;
@@ -135,28 +225,11 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
135225
if (hdr.id->flags & pf_pkcs8) {
136226
err = s_import_pkcs8(pem, l, k, pw_ctx);
137227
goto cleanup;
138-
} else if (hdr.id->flags & pf_public) {
139-
if ((err = der_decode_sequence_flexi(pem, &w, &pub)) != CRYPT_OK) {
140-
goto cleanup;
141-
}
142-
n = 0;
143-
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_SEQUENCE, &seqid);
144-
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_BIT_STRING, NULL);
145-
LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
146-
if ((err = der_flexi_sequence_cmp(pub, flexi_should)) != CRYPT_OK) {
147-
goto cleanup;
148-
}
149-
n = 0;
150-
LTC_SET_DER_FLEXI_CHECK(flexi_should, n++, LTC_ASN1_OBJECT_IDENTIFIER, &id);
151-
LTC_SET_DER_FLEXI_CHECK(flexi_should, n, LTC_ASN1_EOL, NULL);
152-
err = der_flexi_sequence_cmp(seqid, flexi_should);
153-
if (err != CRYPT_OK && err != CRYPT_INPUT_TOO_LONG) {
154-
goto cleanup;
155-
}
156-
if ((err = pk_get_oid_from_asn1(id, &oid_id)) != CRYPT_OK) {
157-
goto cleanup;
158-
}
159-
if ((err = pk_get_pka_id(oid_id, &pka)) != CRYPT_OK) {
228+
} else if (hdr.id->flags == pf_x509) {
229+
err = s_import_x509(pem, l, k);
230+
goto cleanup;
231+
} else if ((hdr.id->flags & pf_public) && hdr.id->pka == LTC_PKA_UNDEF) {
232+
if ((err = s_extract_pka(pem, w, &pka)) != CRYPT_OK) {
160233
goto cleanup;
161234
}
162235
} else if (hdr.encrypted) {
@@ -178,44 +251,18 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
178251
} else {
179252
pka = hdr.id->pka;
180253
}
181-
switch (pka) {
182-
#ifdef LTC_MDSA
183-
case LTC_OID_DSA:
184-
err = dsa_import(pem, l, &k->u.dsa);
185-
k->id = LTC_PKA_DSA;
186-
break;
187-
#endif
188-
#ifdef LTC_MRSA
189-
case LTC_OID_RSA:
190-
err = rsa_import(pem, l, &k->u.rsa);
191-
k->id = LTC_PKA_RSA;
192-
break;
193-
#endif
194-
#ifdef LTC_MECC
195-
case LTC_OID_EC:
196-
err = ecc_import_openssl(pem, l, &k->u.ecc);
197-
k->id = LTC_PKA_EC;
198-
break;
199-
#endif
200-
#ifdef LTC_CURVE25519
201-
case LTC_PKA_ED25519:
202-
err = ed25519_import(pem, l, &k->u.ed25519);
203-
k->id = LTC_PKA_ED25519;
204-
break;
205-
case LTC_PKA_X25519:
206-
err = x25519_import(pem, l, &k->u.x25519);
207-
k->id = LTC_PKA_X25519;
208-
break;
209-
#endif
210-
default:
211-
err = CRYPT_PK_INVALID_TYPE;
212-
goto cleanup;
254+
255+
if (pka < 0
256+
|| pka > sizeof(s_import_openssl_fns)/sizeof(s_import_openssl_fns[0])
257+
|| s_import_openssl_fns[pka] == NULL) {
258+
err = CRYPT_PK_INVALID_TYPE;
259+
goto cleanup;
260+
}
261+
if ((err = s_import_openssl_fns[pka](pem, l, &k->u)) == CRYPT_OK) {
262+
k->id = pka;
213263
}
214264

215265
cleanup:
216-
if (pub) {
217-
der_sequence_free(pub);
218-
}
219266
if (hdr.pw) {
220267
zeromem(hdr.pw->pw, hdr.pw->l);
221268
XFREE(hdr.pw->pw);

src/misc/pem/pem_read.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
#ifdef LTC_PEM
1111

1212
extern const struct str pem_proc_type_encrypted;
13+
#ifdef LTC_SSH
14+
extern const struct str pem_ssh_comment;
15+
#endif
1316
extern const struct str pem_dek_info_start;
1417
extern const struct blockcipher_info pem_dek_infos[];
1518
extern const unsigned long pem_dek_infos_num;
@@ -107,7 +110,10 @@ static int s_pem_decode_headers(struct pem_headers *hdr, struct get_char *g)
107110
switch (has_more_headers) {
108111
case 3:
109112
if (XMEMCMP(buf, pem_proc_type_encrypted.p, pem_proc_type_encrypted.len)) {
110-
s_unget_line(buf, slen, g);
113+
#ifdef LTC_SSH
114+
if (XMEMCMP(buf, pem_ssh_comment.p, pem_ssh_comment.len))
115+
#endif
116+
s_unget_line(buf, slen, g);
111117
if (hdr->id->has_more_headers == maybe)
112118
return CRYPT_OK;
113119
else

0 commit comments

Comments
 (0)