crypto: Remove support for ASN public keys.
[paraslash.git] / gcrypt.c
index 45a1c67d20da0b6d229180de92be10644a63d082..1ae7cfb0deb4fb591dc97bcb5491b7cc54ec920a 100644 (file)
--- a/gcrypt.c
+++ b/gcrypt.c
@@ -15,6 +15,7 @@
 #include "crypt.h"
 #include "crypt_backend.h"
 #include "fd.h"
+#include "base64.h"
 
 //#define GCRYPT_DEBUG 1
 
@@ -212,7 +213,7 @@ static int decode_key(const char *key_file, const char *header_str,
 
        ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
        if (ret < 0)
-               return ret;
+               goto out;
        ret = -E_KEY_MARKER;
        if (strncmp(map, header_str, strlen(header_str)))
                goto unmap;
@@ -239,12 +240,11 @@ static int decode_key(const char *key_file, const char *header_str,
                key[j++] = begin[i];
        }
        key[j] = '\0';
-       blob_size = key_size * 2;
-       blob = para_malloc(blob_size);
-       ret = base64_decode(key, blob, blob_size);
+       ret = base64_decode(key, j, (char **)&blob, &blob_size);
        free(key);
        if (ret < 0)
                goto free_unmap;
+       ret = blob_size;
        goto unmap;
 free_unmap:
        free(blob);
@@ -257,6 +257,7 @@ unmap:
                free(blob);
                blob = NULL;
        }
+out:
        *result = blob;
        return ret;
 }
@@ -300,64 +301,6 @@ static inline int get_long_form_num_length_bytes(unsigned char c)
        return c & 0x7f;
 }
 
-static int find_pubkey_bignum_offset(const unsigned char *data, int len)
-{
-       const unsigned char *p = data, *end = data + len;
-
-       /* the whole thing starts with one sequence */
-       if (*p != ASN1_TYPE_SEQUENCE)
-               return -E_ASN1_PARSE;
-       p++;
-       if (p >= end)
-               return -E_ASN1_PARSE;
-       if (is_short_form(*p))
-               p++;
-       else
-               p += 1 + get_long_form_num_length_bytes(*p);
-       if (p >= end)
-               return -E_ASN1_PARSE;
-       /* another sequence containing the object id, skip it */
-       if (*p != ASN1_TYPE_SEQUENCE)
-               return -E_ASN1_PARSE;
-       p++;
-       if (p >= end)
-               return -E_ASN1_PARSE;
-       if (!is_short_form(*p))
-               return -E_ASN1_PARSE;
-       p += 1 + get_short_form_length(*p);
-       if (p >= end)
-               return -E_ASN1_PARSE;
-       /* all numbers are wrapped in a bit string object that follows */
-       if (*p != ASN1_TYPE_BIT_STRING)
-               return -E_ASN1_PARSE;
-       p++;
-       if (p >= end)
-               return -E_ASN1_PARSE;
-       if (is_short_form(*p))
-               p++;
-       else
-               p += 1 + get_long_form_num_length_bytes(*p);
-       p++; /* skip number of unused bits in the bit string */
-       if (p >= end)
-               return -E_ASN1_PARSE;
-
-       /* next, we have a sequence of two integers (n and e) */
-       if (*p != ASN1_TYPE_SEQUENCE)
-               return -E_ASN1_PARSE;
-       p++;
-       if (p >= end)
-               return -E_ASN1_PARSE;
-       if (is_short_form(*p))
-               p++;
-       else
-               p += 1 + get_long_form_num_length_bytes(*p);
-       if (p >= end)
-               return -E_ASN1_PARSE;
-       if (*p != ASN1_TYPE_INTEGER)
-               return -E_ASN1_PARSE;
-       return p - data;
-}
-
 /*
  * Returns: Number of bytes scanned. This may differ from the value returned via
  * bn_bytes because the latter does not include the ASN.1 prefix and a leading
@@ -387,7 +330,7 @@ static int read_bignum(unsigned char *start, unsigned char *end, gcry_mpi_t *bn,
                for (i = 0; i < num_bytes; i++, cp++)
                        bn_size = (bn_size << 8) + *cp;
        }
-       PARA_DEBUG_LOG("bn_size %d (0x%x)\n", bn_size, bn_size);
+       PARA_DEBUG_LOG("bn_size %d (0x%x)\n", bn_size, (unsigned)bn_size);
        gret = gcry_mpi_scan(bn, GCRYMPI_FMT_STD, cp, bn_size, NULL);
        if (gret) {
                PARA_ERROR_LOG("%s while scanning n\n",
@@ -459,6 +402,7 @@ static int get_private_key(const char *key_file, struct asymmetric_key **result)
        gcry_sexp_t sexp;
        struct asymmetric_key *key;
 
+       *result = NULL;
        ret = decode_key(key_file, PRIVATE_KEY_HEADER, PRIVATE_KEY_FOOTER,
                &blob);
        if (ret < 0)
@@ -537,65 +481,6 @@ free_blob:
        return ret;
 }
 
-/** Public keys start with this header. */
-#define PUBLIC_KEY_HEADER "-----BEGIN PUBLIC KEY-----"
-/** Public keys end with this footer. */
-#define PUBLIC_KEY_FOOTER "-----END PUBLIC KEY-----"
-
-static int get_asn_public_key(const char *key_file, struct asymmetric_key **result)
-{
-       gcry_mpi_t n = NULL, e = NULL;
-       unsigned char *blob, *cp, *end;
-       int blob_size, ret, n_size;
-       gcry_error_t gret;
-       size_t erroff;
-       gcry_sexp_t sexp;
-       struct asymmetric_key *key;
-
-       ret = decode_key(key_file, PUBLIC_KEY_HEADER, PUBLIC_KEY_FOOTER,
-               &blob);
-       if (ret < 0)
-               return ret;
-       blob_size = ret;
-       end = blob + blob_size;
-       ret = find_pubkey_bignum_offset(blob, blob_size);
-       if (ret < 0)
-               goto free_blob;
-       PARA_DEBUG_LOG("decoding public RSA params at offset %d\n", ret);
-       cp = blob + ret;
-
-       ret = read_bignum(cp, end, &n, &n_size);
-       if (ret < 0)
-               goto free_blob;
-       cp += ret;
-
-       ret = read_bignum(cp, end, &e, NULL);
-       if (ret < 0)
-               goto release_n;
-
-       gret = gcry_sexp_build(&sexp, &erroff, RSA_PUBKEY_SEXP, n, e);
-       if (gret) {
-               PARA_ERROR_LOG("offset %zu: %s\n", erroff,
-                       gcry_strerror(gcry_err_code(gret)));
-               ret = -E_SEXP_BUILD;
-               goto release_e;
-       }
-       key = para_malloc(sizeof(*key));
-       key->sexp = sexp;
-       key->num_bytes = n_size;
-       *result = key;
-       ret = n_size;
-       PARA_INFO_LOG("successfully read %u bit asn public key\n", n_size * 8);
-
-release_e:
-       gcry_mpi_release(e);
-release_n:
-       gcry_mpi_release(n);
-free_blob:
-       free(blob);
-       return ret;
-}
-
 static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result)
 {
        int ret;
@@ -605,13 +490,9 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result
        gcry_mpi_t e = NULL, n = NULL;
 
        PARA_DEBUG_LOG("decoding %d byte public rsa-ssh key\n", size);
-       if (size > INT_MAX / 4)
-               return -ERRNO_TO_PARA_ERROR(EOVERFLOW);
-       blob = para_malloc(2 * size);
-       ret = uudecode((char *)data, blob, 2 * size);
+       ret = uudecode((char *)data, size, (char **)&blob, &decoded_size);
        if (ret < 0)
                goto free_blob;
-       decoded_size = ret;
        end = blob + decoded_size;
        dump_buffer("decoded key", blob, decoded_size);
        ret = check_ssh_key_header(blob, decoded_size);
@@ -651,7 +532,7 @@ static int get_ssh_public_key(unsigned char *data, int size, gcry_sexp_t *result
                goto release_n;
        }
        ret = nr_scanned / 32 * 32;
-       PARA_INFO_LOG("successfully read %u bit ssh public key\n", ret * 8);
+       PARA_INFO_LOG("successfully read %d bit ssh public key\n", ret * 8);
 release_n:
        gcry_mpi_release(n);
 release_e:
@@ -661,8 +542,7 @@ free_blob:
        return ret;
 }
 
-int get_asymmetric_key(const char *key_file, int private,
-               struct asymmetric_key **result)
+int get_public_key(const char *key_file, struct asymmetric_key **result)
 {
        int ret, ret2;
        void *map;
@@ -671,17 +551,13 @@ int get_asymmetric_key(const char *key_file, int private,
        gcry_sexp_t sexp;
        struct asymmetric_key *key;
 
-       if (private)
-               return get_private_key(key_file, result);
        ret = mmap_full_file(key_file, O_RDONLY, &map, &map_size, NULL);
        if (ret < 0)
                return ret;
        ret = is_ssh_rsa_key(map, map_size);
        if (!ret) {
-               ret = para_munmap(map, map_size);
-               if (ret < 0)
-                       return ret;
-               return get_asn_public_key(key_file, result);
+               para_munmap(map, map_size);
+               return -E_SSH_PARSE;
        }
        start = map + ret;
        end = map + map_size;
@@ -702,7 +578,7 @@ unmap:
        return ret;
 }
 
-void free_asymmetric_key(struct asymmetric_key *key)
+void free_public_key(struct asymmetric_key *key)
 {
        if (!key)
                return;
@@ -781,6 +657,9 @@ int priv_decrypt(const char *key_file, unsigned char *outbuf,
        gcry_sexp_t in, out, priv_key;
        size_t nbytes;
 
+       ret = check_private_key_file(key_file);
+       if (ret < 0)
+               return ret;
        PARA_INFO_LOG("decrypting %d byte input\n", inlen);
        /* key_file -> asymmetric key priv */
        ret = get_private_key(key_file, &priv);
@@ -831,7 +710,8 @@ in_mpi_release:
 key_release:
        gcry_sexp_release(priv_key);
 free_key:
-       free_asymmetric_key(priv);
+       gcry_sexp_release(priv->sexp);
+       free(priv);
        return ret;
 }