diff --git a/src/lib/eet/Eet.h b/src/lib/eet/Eet.h index b3451fa4fa..de56b18192 100644 --- a/src/lib/eet/Eet.h +++ b/src/lib/eet/Eet.h @@ -2062,6 +2062,26 @@ EAPI void 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. diff --git a/src/lib/eet/eet_lib.c b/src/lib/eet/eet_lib.c index daa6d3b897..ed610f6adc 100644 --- a/src/lib/eet/eet_lib.c +++ b/src/lib/eet/eet_lib.c @@ -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) diff --git a/src/tests/eet/eet_suite.c b/src/tests/eet/eet_suite.c index 7baabe653a..a028d64b90 100644 --- a/src/tests/eet/eet_suite.c +++ b/src/tests/eet/eet_suite.c @@ -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);