Skip to content

Commit c185566

Browse files
committed
Add support for importing PEM public keys
Signed-off-by: Steffen Jaeckel <s@jaeckel.eu>
1 parent 70a3eb6 commit c185566

File tree

10 files changed

+154
-63
lines changed

10 files changed

+154
-63
lines changed

src/headers/tomcrypt_private.h

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,12 +293,18 @@ enum more_headers {
293293
maybe
294294
};
295295

296+
enum pem_flags {
297+
pf_encrypted = 0x01u,
298+
pf_pkcs8 = 0x02u,
299+
pf_public = 0x04u,
300+
pf_encrypted_pkcs8 = pf_encrypted | pf_pkcs8,
301+
};
302+
296303
struct pem_header_id {
297304
struct str start, end;
298305
enum more_headers has_more_headers;
299-
int encrypted;
306+
enum pem_flags flags;
300307
enum ltc_pka_id pka;
301-
int pkcs8;
302308
int (*decrypt)(void *, unsigned long *, void *);
303309
};
304310

src/misc/pem/pem.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,21 @@ const struct pem_header_id pem_std_headers[] = {
1515
SET_CSTR(.start, "-----BEGIN ENCRYPTED PRIVATE KEY-----"),
1616
SET_CSTR(.end, "-----END ENCRYPTED PRIVATE KEY-----"),
1717
.has_more_headers = no,
18-
.encrypted = 1,
19-
.pkcs8 = 1,
18+
.flags = pf_encrypted_pkcs8,
2019
},
2120
{
2221
/* PKCS#8 plain */
2322
SET_CSTR(.start, "-----BEGIN PRIVATE KEY-----"),
2423
SET_CSTR(.end, "-----END PRIVATE KEY-----"),
2524
.has_more_headers = no,
26-
.pkcs8 = 1,
25+
.flags = pf_pkcs8,
26+
},
27+
{
28+
/* Regular (plain) public keys */
29+
SET_CSTR(.start, "-----BEGIN PUBLIC KEY-----"),
30+
SET_CSTR(.end, "-----END PUBLIC KEY-----"),
31+
.has_more_headers = no,
32+
.flags = pf_public,
2733
},
2834
/* Regular plain or encrypted private keys */
2935
{

src/misc/pem/pem_pkcs.c

Lines changed: 100 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -44,13 +44,64 @@ static int s_decrypt_pem(unsigned char *pem, unsigned long *l, const struct pem_
4444
zeromem(iv, sizeof(iv));
4545
return err;
4646
}
47-
typedef int (*pkcs8_import)(const unsigned char *in, unsigned long inlen,
48-
password_ctx *pw_ctx,
49-
void *key);
50-
typedef struct {
51-
enum ltc_oid_id id;
52-
pkcs8_import fn;
53-
} p8_import_st;
47+
48+
static int s_import_pkcs8(unsigned char *pem, unsigned long l, ltc_pka_key *k, const password_ctx *pw_ctx)
49+
{
50+
int err;
51+
enum ltc_oid_id pka;
52+
ltc_asn1_list *alg_id, *priv_key;
53+
ltc_asn1_list *p8_asn1 = NULL;
54+
if ((err = pkcs8_decode_flexi(pem, l, pw_ctx, &p8_asn1)) != CRYPT_OK) {
55+
goto cleanup;
56+
}
57+
if ((err = pkcs8_get_children(p8_asn1, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
58+
goto cleanup;
59+
}
60+
switch (pka) {
61+
#ifdef LTC_MDH
62+
case LTC_OID_DH:
63+
err = dh_import_pkcs8_asn1(alg_id, priv_key, &k->u.dh);
64+
k->id = LTC_PKA_DH;
65+
break;
66+
#endif
67+
#ifdef LTC_MDSA
68+
case LTC_OID_DSA:
69+
err = dsa_import_pkcs8_asn1(alg_id, priv_key, &k->u.dsa);
70+
k->id = LTC_PKA_DSA;
71+
break;
72+
#endif
73+
#ifdef LTC_MRSA
74+
case LTC_OID_RSA:
75+
err = rsa_import_pkcs8_asn1(alg_id, priv_key, &k->u.rsa);
76+
k->id = LTC_PKA_RSA;
77+
break;
78+
#endif
79+
#ifdef LTC_MECC
80+
case LTC_OID_EC:
81+
err = ecc_import_pkcs8_asn1(alg_id, priv_key, &k->u.ecc);
82+
k->id = LTC_PKA_EC;
83+
break;
84+
#endif
85+
#ifdef LTC_CURVE25519
86+
case LTC_OID_X25519:
87+
err = x25519_import_pkcs8_asn1(alg_id, priv_key, &k->u.x25519);
88+
k->id = LTC_PKA_X25519;
89+
break;
90+
case LTC_OID_ED25519:
91+
err = ed25519_import_pkcs8_asn1(alg_id, priv_key, &k->u.ed25519);
92+
k->id = LTC_PKA_ED25519;
93+
break;
94+
#endif
95+
default:
96+
err = CRYPT_PK_INVALID_TYPE;
97+
}
98+
99+
cleanup:
100+
if (p8_asn1) {
101+
der_sequence_free(p8_asn1);
102+
}
103+
return err;
104+
}
54105

55106
static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
56107
{
@@ -59,7 +110,10 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
59110
int err = CRYPT_ERROR;
60111
struct pem_headers hdr = { 0 };
61112
struct password pw;
62-
ltc_asn1_list *p8_asn1 = NULL;
113+
ltc_asn1_list *pub = NULL, *seqid, *id;
114+
der_flexi_check flexi_should[4];
115+
enum ltc_oid_id oid_id;
116+
enum ltc_pka_id pka;
63117
XMEMSET(k, 0, sizeof(*k));
64118
w = LTC_PEM_READ_BUFSIZE * 2;
65119
retry:
@@ -78,54 +132,33 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
78132
if (hdr.id == NULL)
79133
goto cleanup;
80134
l = w;
81-
if (hdr.id->pkcs8) {
82-
enum ltc_oid_id pka;
83-
ltc_asn1_list *alg_id, *priv_key;
84-
if ((err = pkcs8_decode_flexi(pem, l, pw_ctx, &p8_asn1)) != CRYPT_OK) {
135+
if (hdr.id->flags & pf_pkcs8) {
136+
err = s_import_pkcs8(pem, l, k, pw_ctx);
137+
goto cleanup;
138+
} else if (hdr.id->flags & pf_public) {
139+
if ((err = der_decode_sequence_flexi(pem, &w, &pub)) != CRYPT_OK) {
85140
goto cleanup;
86141
}
87-
if ((err = pkcs8_get_children(p8_asn1, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
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) {
88147
goto cleanup;
89148
}
90-
switch (pka) {
91-
#ifdef LTC_MDH
92-
case LTC_OID_DH:
93-
err = dh_import_pkcs8_asn1(alg_id, priv_key, &k->u.dh);
94-
k->id = LTC_PKA_DH;
95-
break;
96-
#endif
97-
#ifdef LTC_MDSA
98-
case LTC_OID_DSA:
99-
err = dsa_import_pkcs8_asn1(alg_id, priv_key, &k->u.dsa);
100-
k->id = LTC_PKA_DSA;
101-
break;
102-
#endif
103-
#ifdef LTC_MRSA
104-
case LTC_OID_RSA:
105-
err = rsa_import_pkcs8_asn1(alg_id, priv_key, &k->u.rsa);
106-
k->id = LTC_PKA_RSA;
107-
break;
108-
#endif
109-
#ifdef LTC_MECC
110-
case LTC_OID_EC:
111-
err = ecc_import_pkcs8_asn1(alg_id, priv_key, &k->u.ecc);
112-
k->id = LTC_PKA_EC;
113-
break;
114-
#endif
115-
#ifdef LTC_CURVE25519
116-
case LTC_OID_X25519:
117-
err = x25519_import_pkcs8_asn1(alg_id, priv_key, &k->u.x25519);
118-
k->id = LTC_PKA_X25519;
119-
break;
120-
case LTC_OID_ED25519:
121-
err = ed25519_import_pkcs8_asn1(alg_id, priv_key, &k->u.ed25519);
122-
k->id = LTC_PKA_ED25519;
123-
break;
124-
#endif
125-
default:
126-
err = CRYPT_PK_INVALID_TYPE;
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) {
160+
goto cleanup;
127161
}
128-
goto cleanup;
129162
} else if (hdr.encrypted) {
130163
if ((pw_ctx == NULL) || (pw_ctx->callback == NULL)) {
131164
err = CRYPT_PW_CTX_MISSING;
@@ -141,8 +174,11 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
141174
if ((err = s_decrypt_pem(pem, &l, &hdr)) != CRYPT_OK) {
142175
goto cleanup;
143176
}
177+
pka = hdr.id->pka;
178+
} else {
179+
pka = hdr.id->pka;
144180
}
145-
switch (hdr.id->pka) {
181+
switch (pka) {
146182
#ifdef LTC_MDSA
147183
case LTC_OID_DSA:
148184
err = dsa_import(pem, l, &k->u.dsa);
@@ -160,15 +196,25 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
160196
err = ecc_import_openssl(pem, l, &k->u.ecc);
161197
k->id = LTC_PKA_EC;
162198
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;
163209
#endif
164210
default:
165211
err = CRYPT_PK_INVALID_TYPE;
166212
goto cleanup;
167213
}
168214

169215
cleanup:
170-
if (p8_asn1) {
171-
der_sequence_free(p8_asn1);
216+
if (pub) {
217+
der_sequence_free(pub);
172218
}
173219
if (hdr.pw) {
174220
zeromem(hdr.pw->pw, hdr.pw->l);

src/misc/pem/pem_read.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ int pem_read(void *pem, unsigned long *w, struct pem_headers *hdr, struct get_ch
167167
return CRYPT_INVALID_PACKET;
168168
}
169169

170-
hdr->encrypted = hdr->id->encrypted;
170+
hdr->encrypted = hdr->id->flags & pf_encrypted;
171171
if ((err = s_pem_decode_headers(hdr, g)) != CRYPT_OK)
172172
return err;
173173

tests/pem/dsa-pub.pem

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MIIBtjCCASsGByqGSM44BAEwggEeAoGBAMUKN1Fcq9YY1aJwvUpva0r54TmVDyuZ
3+
OH2aZNZMtZZ63O2sqKzGG2Va3tsAYSUaGCzuoQeQYl5NEjGQxwMh+gnnsXPXjq/b
4+
/b+z763RoSoDbecGkkqFKv96AWZTH+rGZ0GEWsBs7WL5wmJiBaT6SKBm7DXJqBH+
5+
uYGr7r4xtr/PAhUAqlvX9OUGJBPliDXKAMemNXFhlMUCgYA7kuT/WSkVCwiZWnvy
6+
rRRAVW+gR/+QmbNEs9T8RRUFrmciQ5y6NxCliUc37Mz1rq2otHo1y52TXO3msH6W
7+
lMSmDH3WcIoJT4FKDsIT++sWv+qk9Fb/cjAF3opEP77GhSZV1i0dHtsV2qRFgzwX
8+
l5gLjYfzSQ2QvamrZ26HaHIj3AOBhAACgYBTFrD7v1mKXlWVwU+sQ7gIU+bPDZIj
9+
+rGEWVI5v8vyLTg63ZNSBUl+KxLEYXPjb1S9luWnqqlaWKS3Z9LAvcgesToST5jA
10+
Be85XWq6tws72LeV3XluotKEc0cDiLRk2bm4T/HJNLv5c2b1fC4R/sMx5gg4WWeB
11+
621BJ9cNdK+gNQ==
12+
-----END PUBLIC KEY-----

tests/pem/ecc-pub.pem

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MIIBMzCB7AYHKoZIzj0CATCB4AIBATAsBgcqhkjOPQEBAiEA////////////////
3+
/////////////////////v///C8wRAQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
4+
AAAAAAAAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBEEEeb5m
5+
fvncu6xVoGKVzocLBwKb/NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0
6+
SKaFVBmcR9CP+xDUuAIhAP////////////////////66rtzmr0igO7/SXozQNkFB
7+
AgEBA0IABCr5C9q+cWae0c8S0CSvurZ/+5YnPi+9HtX5jWxzncUWkb2yuRtAEFq3
8+
bG4yW/djYpQkJNvsP4vlbktkNzEkeU0=
9+
-----END PUBLIC KEY-----

tests/pem/ed25519-pub.pem

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=
3+
-----END PUBLIC KEY-----

tests/pem/rsa-pub.pem

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPmt5kitrIMyCp14MxGVSymoWn
3+
obd1M7aprIQks97bfYUtlmXlP3KVJJ8oaMpP20QcPmASit0mpev/C17UiDhJKm5b
4+
vxI3R70Fa7zb8+7kEY5BaHxhE9dCyIC+No/cCItPrKTidgzJY2xJWJPtzKrcJTsK
5+
YD+LVDrDTTHnlKRE/QIDAQAB
6+
-----END PUBLIC KEY-----

tests/pem/x25519-pub.pem

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
-----BEGIN PUBLIC KEY-----
2+
MCowBQYDK2VuAyEAk4OBwskGGOapbeWgTLKCz4XM2PzZorXOuyJQEbMmVmk=
3+
-----END PUBLIC KEY-----

tests/pem_test.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -51,17 +51,17 @@ static int s_key_cmp(ltc_pka_key *key)
5151
switch (key->id) {
5252
case LTC_PKA_DSA:
5353
#if defined(LTC_MDSA)
54-
return dsa_key_cmp(PK_PRIVATE, &s_dsa_key_should, &key->u.dsa);
54+
return dsa_key_cmp(key->u.dsa.type, &s_dsa_key_should, &key->u.dsa);
5555
#endif
5656
break;
5757
case LTC_PKA_RSA:
5858
#if defined(LTC_MRSA)
59-
return rsa_key_cmp(PK_PRIVATE, &s_rsa_key_should, &key->u.rsa);
59+
return rsa_key_cmp(key->u.rsa.type, &s_rsa_key_should, &key->u.rsa);
6060
#endif
6161
break;
6262
case LTC_PKA_EC:
6363
#if defined(LTC_MECC)
64-
return ecc_key_cmp(PK_PRIVATE, &s_ecc_key_should, &key->u.ecc);
64+
return ecc_key_cmp(key->u.ecc.type, &s_ecc_key_should, &key->u.ecc);
6565
#endif
6666
break;
6767
case LTC_PKA_ED25519:

0 commit comments

Comments
 (0)