eet - add new api to verify eet file against stored cert
authorCarsten Haitzler (Rasterman) <raster@rasterman.com>
Fri, 28 Nov 2014 08:54:39 +0000 (17:54 +0900)
committerCarsten Haitzler (Rasterman) <raster@rasterman.com>
Fri, 28 Nov 2014 08:56:27 +0000 (17:56 +0900)
this api makes it far more obvious as to how to verify an eet file via
the eet identify mechanisms that use x509 certificates to sign files.
this is consistent with the api used to generate the key for sigining
thus you can use the same certificate file to compare against for
identify.

@feature

src/lib/eet/Eet.h
src/lib/eet/eet_lib.c
src/tests/eet/eet_suite.c

index b3451fa..de56b18 100644 (file)
@@ -2063,6 +2063,26 @@ eet_identity_print(Eet_Key *key,
                    FILE *out);
 
 /**
+ * Compare the identify certificate of an eet file against a stored one
+ *
+ * @param ef The file handle to check the identify of
+ * @param certificate_file The path to the certificate file
+ * @return EINA_TRUE if the certificates match, otherwise EINA_FALSE;
+ *
+ * The @p ef file handle mus be valid, and a signed file, otherwise
+ * checking will fail. The path to the certificate file must be a valid
+ * file path to a 'pem' format file (the same used for siging with
+ * eet_identity_open() as a certificate file).
+ * 
+ * @warning You need to compile signature support in EET.
+ * @since 1.13
+ * @ingroup Eet_Cipher_Group
+ */
+EAPI Eina_Bool
+eet_identity_verify(Eet_File *ef,
+                    const char *certificate_file);
+
+/**
  * Get the x509 der certificate associated with an Eet_File. Will return NULL
  * if the file is not signed.
  *
index daa6d3b..ed610f6 100644 (file)
@@ -1676,6 +1676,154 @@ eet_mode_get(Eet_File *ef)
       return ef->mode;
 }
 
+static const char *_b64_table =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static Eina_Bool
+_b64_is(char c)
+{
+   const char *p;
+
+   if (!c) return EINA_FALSE;
+   p = strchr(_b64_table, c);
+   if (p >= _b64_table) return EINA_TRUE;
+   return EINA_FALSE;
+}
+
+static unsigned char
+_b64_val(char c)
+{
+   const char *p = strchr(_b64_table, c);
+   if (p) return p - _b64_table;
+   return 0;
+}
+
+static int
+_b64_dec(unsigned char *dst, const char *src, int len)
+{
+   unsigned char *p = dst;
+   *dst = 0;
+
+   if (!*src) return 0;
+   do
+     {
+        unsigned char a = _b64_val(src[0]);
+        unsigned char b = _b64_val(src[1]);
+        unsigned char c = _b64_val(src[2]);
+        unsigned char d = _b64_val(src[3]);
+
+        *p++ = (a << 2) | (b >> 4);
+        *p++ = (b << 4) | (c >> 2);
+        *p++ = (c << 6) | d;
+
+        if (!_b64_is(src[1]))
+          {
+             p -= 2;
+             break;
+          }
+        else if (!_b64_is(src[2]))
+          {
+             p -= 2;
+             break;
+          }
+        else if (!_b64_is(src[3]))
+          {
+             p--;
+             break;
+          }
+        src += 4;
+        while (*src && ((*src == 13) || (*src == 10))) src++;
+     }
+   while ((len -= 4));
+   *p = 0;
+   return (int)(p - dst);
+}
+
+static unsigned char *
+_base64_dec(const char *file, int *size_ret)
+{
+   char buf[4096], *p, *end;
+   unsigned char *data = NULL;
+   Eina_Binbuf *binbuf;
+   FILE *f;
+
+   f = fopen(file, "rb");
+   if (!f) return NULL;
+   binbuf = eina_binbuf_new();
+   if (!binbuf)
+     {
+        fclose(f);
+        return NULL;
+     }
+   while (fgets(buf, sizeof(buf) - 1, f))
+     {
+        buf[sizeof(buf) - 1] = 0;
+        // check where first invalid char in a line is
+        for (p = buf; *p; p++)
+          {
+             // this is the first invalid char
+             if ((*p != '=') && (!_b64_is(*p))) break;
+          }
+        end = p;
+        // go from line start to (but not including) first invalid char
+        if (((end - buf) > 0) && (((end - buf) % 4) == 0))
+          {
+             unsigned char *tmp = malloc((end - buf + 4) * 2);
+
+             if (tmp)
+               {
+                  int len = _b64_dec(tmp, buf, end - buf);
+                  char *str = malloc(end - buf + 1);
+                  strncpy(str, buf, end - buf);
+                  str[end - buf] = 0;
+                  free(str);
+                  eina_binbuf_append_length(binbuf, tmp, len);
+                  free(tmp);
+               }
+          }
+     }
+   fclose(f);
+   // as long as data is less than a mb - we have a cert that is possibly ok
+   if (eina_binbuf_length_get(binbuf) < (1 * 1024 * 1024))
+     {
+        *size_ret = eina_binbuf_length_get(binbuf);
+        data = eina_binbuf_string_steal(binbuf);
+     }
+   eina_binbuf_free(binbuf);
+   return data;
+}
+
+EAPI Eina_Bool
+eet_identity_verify(Eet_File   *ef,
+                    const char *certificate_file)
+{
+   unsigned char *cert;
+   int cert_len;
+
+   if (eet_check_pointer(ef))
+     return EINA_FALSE;
+
+   if (!ef->x509_der)
+     return EINA_FALSE;
+
+   cert = _base64_dec(certificate_file, &cert_len);
+   if (!cert)
+     return EINA_FALSE;
+
+   if (cert_len != ef->x509_length)
+     {
+        free(cert);
+        return EINA_FALSE;
+     }
+   if (memcmp(ef->x509_der, cert, cert_len))
+     {
+        free(cert);
+        return EINA_FALSE;
+     }
+   free(cert);
+   return EINA_TRUE;
+}
+
 EAPI const void *
 eet_identity_x509(Eet_File *ef,
                   int      *der_length)
index 7baabe6..a028d64 100644 (file)
@@ -1752,6 +1752,9 @@ START_TEST(eet_identity_simple)
    ef = eet_open(file, EET_FILE_MODE_READ);
    fail_if(!ef);
 
+   /* check that the certificates match */
+   fail_if(!eet_identity_verify(ef, _cert_pem));
+
    test = eet_read(ef, "keys/tests", &size);
    fail_if(!test);
    fail_if(size != (int)strlen(buffer) + 1);