Browse Source

Add support for importing PEM public keys

Signed-off-by: Steffen Jaeckel <[email protected]>
Steffen Jaeckel 2 years ago
parent
commit
23eb8f97bc

+ 8 - 2
src/headers/tomcrypt_private.h

@@ -293,12 +293,18 @@ enum more_headers {
    maybe
 };
 
+enum pem_flags {
+   pf_encrypted = 0x01u,
+   pf_pkcs8 = 0x02u,
+   pf_public = 0x04u,
+   pf_encrypted_pkcs8 = pf_encrypted | pf_pkcs8,
+};
+
 struct pem_header_id {
    struct str start, end;
    enum more_headers has_more_headers;
-   int encrypted;
+   enum pem_flags flags;
    enum ltc_pka_id pka;
-   int pkcs8;
    int (*decrypt)(void *, unsigned long *, void *);
 };
 

+ 9 - 3
src/misc/pem/pem.c

@@ -15,15 +15,21 @@ const struct pem_header_id pem_std_headers[] = {
      SET_CSTR(.start, "-----BEGIN ENCRYPTED PRIVATE KEY-----"),
      SET_CSTR(.end, "-----END ENCRYPTED PRIVATE KEY-----"),
      .has_more_headers = no,
-     .encrypted = 1,
-     .pkcs8 = 1,
+     .flags = pf_encrypted_pkcs8,
    },
    {
      /* PKCS#8 plain */
      SET_CSTR(.start, "-----BEGIN PRIVATE KEY-----"),
      SET_CSTR(.end, "-----END PRIVATE KEY-----"),
      .has_more_headers = no,
-     .pkcs8 = 1,
+     .flags = pf_pkcs8,
+   },
+   {
+     /* Regular (plain) public keys */
+     SET_CSTR(.start, "-----BEGIN PUBLIC KEY-----"),
+     SET_CSTR(.end, "-----END PUBLIC KEY-----"),
+     .has_more_headers = no,
+     .flags = pf_public,
    },
    /* Regular plain or encrypted private keys */
    {

+ 100 - 54
src/misc/pem/pem_pkcs.c

@@ -44,13 +44,64 @@ static int s_decrypt_pem(unsigned char *pem, unsigned long *l, const struct pem_
    zeromem(iv, sizeof(iv));
    return err;
 }
-typedef int (*pkcs8_import)(const unsigned char *in, unsigned long inlen,
-                                   password_ctx *pw_ctx,
-                                           void *key);
-typedef struct {
-   enum ltc_oid_id id;
-   pkcs8_import fn;
-} p8_import_st;
+
+static int s_import_pkcs8(unsigned char *pem, unsigned long l, ltc_pka_key *k, const password_ctx *pw_ctx)
+{
+   int err;
+   enum ltc_oid_id pka;
+   ltc_asn1_list *alg_id, *priv_key;
+   ltc_asn1_list *p8_asn1 = NULL;
+   if ((err = pkcs8_decode_flexi(pem, l, pw_ctx, &p8_asn1)) != CRYPT_OK) {
+      goto cleanup;
+   }
+   if ((err = pkcs8_get_children(p8_asn1, &pka, &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;
+   }
+
+cleanup:
+   if (p8_asn1) {
+      der_sequence_free(p8_asn1);
+   }
+   return err;
+}
 
 static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_ctx)
 {
@@ -59,7 +110,10 @@ static int s_decode(struct get_char *g, ltc_pka_key *k, const password_ctx *pw_c
    int err = CRYPT_ERROR;
    struct pem_headers hdr = { 0 };
    struct password pw;
-   ltc_asn1_list *p8_asn1 = NULL;
+   ltc_asn1_list *pub = NULL, *seqid, *id;
+   der_flexi_check flexi_should[4];
+   enum ltc_oid_id oid_id;
+   enum ltc_pka_id pka;
    XMEMSET(k, 0, sizeof(*k));
    w = LTC_PEM_READ_BUFSIZE * 2;
 retry:
@@ -78,54 +132,33 @@ retry:
    if (hdr.id == NULL)
       goto cleanup;
    l = w;
-   if (hdr.id->pkcs8) {
-      enum ltc_oid_id pka;
-      ltc_asn1_list *alg_id, *priv_key;
-      if ((err = pkcs8_decode_flexi(pem, l, pw_ctx, &p8_asn1)) != CRYPT_OK) {
+   if (hdr.id->flags & pf_pkcs8) {
+      err = s_import_pkcs8(pem, l, k, pw_ctx);
+      goto cleanup;
+   } else if (hdr.id->flags & pf_public) {
+      if ((err = der_decode_sequence_flexi(pem, &w, &pub)) != CRYPT_OK) {
          goto cleanup;
       }
-      if ((err = pkcs8_get_children(p8_asn1, &pka, &alg_id, &priv_key)) != CRYPT_OK) {
+      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) {
          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;
+      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) {
+         goto cleanup;
+      }
+      if ((err = pk_get_oid_from_asn1(id, &oid_id)) != CRYPT_OK) {
+         goto cleanup;
+      }
+      if ((err = pk_get_pka_id(oid_id, &pka)) != CRYPT_OK) {
+         goto cleanup;
       }
-      goto cleanup;
    } else if (hdr.encrypted) {
       if ((pw_ctx == NULL) || (pw_ctx->callback == NULL)) {
          err = CRYPT_PW_CTX_MISSING;
@@ -141,8 +174,11 @@ retry:
       if ((err = s_decrypt_pem(pem, &l, &hdr)) != CRYPT_OK) {
          goto cleanup;
       }
+      pka = hdr.id->pka;
+   } else {
+      pka = hdr.id->pka;
    }
-   switch (hdr.id->pka) {
+   switch (pka) {
 #ifdef LTC_MDSA
       case LTC_OID_DSA:
          err = dsa_import(pem, l, &k->u.dsa);
@@ -160,6 +196,16 @@ retry:
          err = ecc_import_openssl(pem, l, &k->u.ecc);
          k->id = LTC_PKA_EC;
          break;
+#endif
+#ifdef LTC_CURVE25519
+      case LTC_PKA_ED25519:
+         err = ed25519_import(pem, l, &k->u.ed25519);
+         k->id = LTC_PKA_ED25519;
+         break;
+      case LTC_PKA_X25519:
+         err = x25519_import(pem, l, &k->u.x25519);
+         k->id = LTC_PKA_X25519;
+         break;
 #endif
       default:
          err = CRYPT_PK_INVALID_TYPE;
@@ -167,8 +213,8 @@ retry:
    }
 
 cleanup:
-   if (p8_asn1) {
-      der_sequence_free(p8_asn1);
+   if (pub) {
+      der_sequence_free(pub);
    }
    if (hdr.pw) {
       zeromem(hdr.pw->pw, hdr.pw->l);

+ 1 - 1
src/misc/pem/pem_read.c

@@ -167,7 +167,7 @@ int pem_read(void *pem, unsigned long *w, struct pem_headers *hdr, struct get_ch
       return CRYPT_INVALID_PACKET;
    }
 
-   hdr->encrypted = hdr->id->encrypted;
+   hdr->encrypted = hdr->id->flags & pf_encrypted;
    if ((err = s_pem_decode_headers(hdr, g)) != CRYPT_OK)
       return err;
 

+ 12 - 0
tests/pem/dsa-pub.pem

@@ -0,0 +1,12 @@
+-----BEGIN PUBLIC KEY-----
+MIIBtjCCASsGByqGSM44BAEwggEeAoGBAMUKN1Fcq9YY1aJwvUpva0r54TmVDyuZ
+OH2aZNZMtZZ63O2sqKzGG2Va3tsAYSUaGCzuoQeQYl5NEjGQxwMh+gnnsXPXjq/b
+/b+z763RoSoDbecGkkqFKv96AWZTH+rGZ0GEWsBs7WL5wmJiBaT6SKBm7DXJqBH+
+uYGr7r4xtr/PAhUAqlvX9OUGJBPliDXKAMemNXFhlMUCgYA7kuT/WSkVCwiZWnvy
+rRRAVW+gR/+QmbNEs9T8RRUFrmciQ5y6NxCliUc37Mz1rq2otHo1y52TXO3msH6W
+lMSmDH3WcIoJT4FKDsIT++sWv+qk9Fb/cjAF3opEP77GhSZV1i0dHtsV2qRFgzwX
+l5gLjYfzSQ2QvamrZ26HaHIj3AOBhAACgYBTFrD7v1mKXlWVwU+sQ7gIU+bPDZIj
++rGEWVI5v8vyLTg63ZNSBUl+KxLEYXPjb1S9luWnqqlaWKS3Z9LAvcgesToST5jA
+Be85XWq6tws72LeV3XluotKEc0cDiLRk2bm4T/HJNLv5c2b1fC4R/sMx5gg4WWeB
+621BJ9cNdK+gNQ==
+-----END PUBLIC KEY-----

+ 9 - 0
tests/pem/ecc-pub.pem

@@ -0,0 +1,9 @@
+-----BEGIN PUBLIC KEY-----
+MIIBMzCB7AYHKoZIzj0CATCB4AIBATAsBgcqhkjOPQEBAiEA////////////////
+/////////////////////v///C8wRAQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+AAAAAAAAAAAEIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBEEEeb5m
+fvncu6xVoGKVzocLBwKb/NstzijZWfKBWxb4F5hIOtp3JqPEZV2k+/wOEQio/Re0
+SKaFVBmcR9CP+xDUuAIhAP////////////////////66rtzmr0igO7/SXozQNkFB
+AgEBA0IABCr5C9q+cWae0c8S0CSvurZ/+5YnPi+9HtX5jWxzncUWkb2yuRtAEFq3
+bG4yW/djYpQkJNvsP4vlbktkNzEkeU0=
+-----END PUBLIC KEY-----

+ 3 - 0
tests/pem/ed25519-pub.pem

@@ -0,0 +1,3 @@
+-----BEGIN PUBLIC KEY-----
+MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=
+-----END PUBLIC KEY-----

+ 6 - 0
tests/pem/rsa-pub.pem

@@ -0,0 +1,6 @@
+-----BEGIN PUBLIC KEY-----
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDPmt5kitrIMyCp14MxGVSymoWn
+obd1M7aprIQks97bfYUtlmXlP3KVJJ8oaMpP20QcPmASit0mpev/C17UiDhJKm5b
+vxI3R70Fa7zb8+7kEY5BaHxhE9dCyIC+No/cCItPrKTidgzJY2xJWJPtzKrcJTsK
+YD+LVDrDTTHnlKRE/QIDAQAB
+-----END PUBLIC KEY-----

+ 3 - 0
tests/pem/x25519-pub.pem

@@ -0,0 +1,3 @@
+-----BEGIN PUBLIC KEY-----
+MCowBQYDK2VuAyEAk4OBwskGGOapbeWgTLKCz4XM2PzZorXOuyJQEbMmVmk=
+-----END PUBLIC KEY-----

+ 3 - 3
tests/pem_test.c

@@ -51,17 +51,17 @@ static int s_key_cmp(ltc_pka_key *key)
    switch (key->id) {
       case LTC_PKA_DSA:
 #if defined(LTC_MDSA)
-         return dsa_key_cmp(PK_PRIVATE, &s_dsa_key_should, &key->u.dsa);
+         return dsa_key_cmp(key->u.dsa.type, &s_dsa_key_should, &key->u.dsa);
 #endif
          break;
       case LTC_PKA_RSA:
 #if defined(LTC_MRSA)
-         return rsa_key_cmp(PK_PRIVATE, &s_rsa_key_should, &key->u.rsa);
+         return rsa_key_cmp(key->u.rsa.type, &s_rsa_key_should, &key->u.rsa);
 #endif
          break;
       case LTC_PKA_EC:
 #if defined(LTC_MECC)
-         return ecc_key_cmp(PK_PRIVATE, &s_ecc_key_should, &key->u.ecc);
+         return ecc_key_cmp(key->u.ecc.type, &s_ecc_key_should, &key->u.ecc);
 #endif
          break;
       case LTC_PKA_ED25519: