From 46b7796946d58e83cd24dbed2b9de670d7cf4937 Mon Sep 17 00:00:00 2001 From: Cedric BAIL Date: Mon, 8 Sep 2008 09:19:57 +0000 Subject: [PATCH] Add signature support in eet. You can use eet -s to sign a eet file and eet -c to check its signature. The current code doesn't check any certificate trust path, only if the signature match the certificate and that the certificate could be loaded. If that's not the case, eet_open will fail. If the file is not signed, eet_open will just continue to succeed. SVN revision: 35882 --- legacy/eet/configure.in | 52 +++++ legacy/eet/src/bin/eet_main.c | 58 ++++++ legacy/eet/src/lib/Eet.h | 64 +++++- legacy/eet/src/lib/Eet_private.h | 26 +++ legacy/eet/src/lib/Makefile.am | 4 +- legacy/eet/src/lib/eet_cypher.c | 335 +++++++++++++++++++++++++++++++ legacy/eet/src/lib/eet_lib.c | 104 +++++++++- legacy/eet/src/tests/cert.pem | 22 ++ legacy/eet/src/tests/eet_suite.c | 84 ++++++++ legacy/eet/src/tests/key.pem | 15 ++ 10 files changed, 760 insertions(+), 4 deletions(-) create mode 100644 legacy/eet/src/lib/eet_cypher.c create mode 100644 legacy/eet/src/tests/cert.pem create mode 100644 legacy/eet/src/tests/key.pem diff --git a/legacy/eet/configure.in b/legacy/eet/configure.in index ebf301e28b..21026ee0be 100644 --- a/legacy/eet/configure.in +++ b/legacy/eet/configure.in @@ -143,6 +143,54 @@ fi AM_CONDITIONAL(EET_ENABLE_TESTS, test "x${enable_tests}" = "xyes") +dnl Openssl support +want_openssl="auto" +have_openssl="no" +AC_ARG_ENABLE(openssl, + [AC_HELP_STRING([--disable-openssl], [disable openssl eet support])], + [ want_openssl=$enableval ] +) +if test "x$want_openssl" = "xyes" -o "x$want_openssl" = "xauto"; then + PKG_CHECK_MODULES(OPENSSL, openssl, + [ + have_openssl="yes" + AC_DEFINE(HAVE_OPENSSL, 1, [Have Openssl support]) + ], + [ + if test "x$use_strict" = "xyes"; then + AC_MSG_ERROR([Openssl not found (strict dependencies checking)]) + fi + ]) +fi + +dnl Crypto option +want_cypher="yes" +have_cypher="no" +want_signature="yes" +have_signature="no" + +AC_MSG_CHECKING(whether to activate cypher support in eet) +AC_ARG_ENABLE(cypher, + [AC_HELP_STRING([--disable-cypher], [disable cypher support for eet API])], + [ want_cypher=$enableval ] +) +if test "x$have_openssl" = "xyes" -a "x$want_cypher" = "xyes"; then + have_cypher="yes" + AC_DEFINE(HAVE_CYPHER, 1, [Have cypher support built in eet]) +fi +AC_MSG_RESULT($have_cypher) + +AC_MSG_CHECKING(whether to activate signature support in eet) +AC_ARG_ENABLE(signature, + [AC_HELP_STRING([--disable-signature], [disable signature file support for eet])], + [ want_signature=$enableval ] +) +if test "x$have_openssl" = "xyes" -a "x$want_signature" = "xyes"; then + have_signature="yes" + AC_DEFINE(HAVE_SIGNATURE, 1, [Have signature support for eet file]) +fi +AC_MSG_RESULT($have_signature) + dnl Coverage AC_ARG_ENABLE(coverage, @@ -241,6 +289,10 @@ echo "------------------------------------------------------------------------" echo echo "Configuration Options Summary:" echo +echo " Openssl..............: ${have_openssl}" +echo " Cypher support.....: ${have_cypher}" +echo " Signature..........: ${have_signature}" + echo " Tests................: ${enable_tests}" echo " Coverage.............: ${enable_coverage}" echo diff --git a/legacy/eet/src/bin/eet_main.c b/legacy/eet/src/bin/eet_main.c index 539cec8854..0db402641a 100644 --- a/legacy/eet/src/bin/eet_main.c +++ b/legacy/eet/src/bin/eet_main.c @@ -200,6 +200,50 @@ do_eet_remove(const char *file, const char *key) eet_close(ef); } +static void +do_eet_check(const char *file) +{ + Eet_File *ef; + const void *der; + int der_length; + + ef = eet_open(file, EET_FILE_MODE_READ); + if (!ef) + { + fprintf(stdout, "checking signature of `%s` failed\n", file); + exit(-1); + } + + der = eet_identity_x509(ef, &der_length); + + eet_identity_certificate_print(der, der_length, stdout); + + eet_close(ef); +} + +static void +do_eet_sign(const char *file, const char *private_key, const char *public_key) +{ + Eet_File *ef; + Eet_Key *key; + + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + if (!ef) + { + fprintf(stdout, "cannot open for read+write: %s.\n", file); + exit(-1); + } + + key = eet_identity_open(public_key, private_key, NULL); + + fprintf(stdout, "Using the following key to sign `%s`.\n", file); + eet_identity_print(key, stdout); + + eet_identity_set(ef, key); + + eet_close(ef); +} + int main(int argc, char **argv) { @@ -214,6 +258,8 @@ main(int argc, char **argv) " eet -i FILE.EET KEY IN-FILE COMPRESS insert data to KEY in FILE.EET from IN-FILE and if COMPRESS is 1, compress it\n" " eet -e FILE.EET KEY IN-FILE COMPRESS insert and encode to KEY in FILE.EET from IN-FILE and if COMPRESS is 1, compress it\n" " eet -r FILE.EET KEY remove KEY in FILE.EET\n" + " eet -c FILE.EET report and check the signature information of an eet file\n" + " eet -s FILE.EET PRIVATE_KEY PUBLIC_KEY sign FILE.EET with PRIVATE_KEY and attach PUBLIC_KEY as it's certificate\n" ); eet_shutdown(); return -1; @@ -250,6 +296,18 @@ main(int argc, char **argv) { goto help; } + else if ((!strcmp(argv[1], "-c")) && (argc > 2)) + { + do_eet_check(argv[2]); + } + else if ((!strcmp(argv[1], "-s")) && (argc > 4)) + { + do_eet_sign(argv[2], argv[3], argv[4]); + } + else + { + goto help; + } eet_shutdown(); return 0; } diff --git a/legacy/eet/src/lib/Eet.h b/legacy/eet/src/lib/Eet.h index 2f52aab8b6..c528bc2e8e 100644 --- a/legacy/eet/src/lib/Eet.h +++ b/legacy/eet/src/lib/Eet.h @@ -2,6 +2,7 @@ #define _EET_H #include +#include #ifdef EAPI # undef EAPI @@ -86,12 +87,19 @@ extern "C" { EET_ERROR_WRITE_ERROR_FILE_TOO_BIG, EET_ERROR_WRITE_ERROR_IO_ERROR, EET_ERROR_WRITE_ERROR_OUT_OF_SPACE, - EET_ERROR_WRITE_ERROR_FILE_CLOSED + EET_ERROR_WRITE_ERROR_FILE_CLOSED, + EET_ERROR_MMAP_FAILED, + EET_ERROR_X509_ENCODING_FAILED, + EET_ERROR_SIGNATURE_FAILED, + EET_ERROR_INVALID_SIGNATURE, + EET_ERROR_NOT_SIGNED, + EET_ERROR_NOT_IMPLEMENTED } Eet_Error; typedef struct _Eet_File Eet_File; typedef struct _Eet_Dictionary Eet_Dictionary; typedef struct _Eet_Data_Descriptor Eet_Data_Descriptor; + typedef struct _Eet_Key Eet_Key; typedef struct _Eet_Data_Descriptor_Class Eet_Data_Descriptor_Class; @@ -247,6 +255,60 @@ extern "C" { */ EAPI Eet_Error eet_close(Eet_File *ef); + /** + * Callback used to request if needed the password of a private key. + * + * @since 2.0.0 + */ + typedef int (*Eet_Key_Password_Callback)(char *buffer, int size, int rwflag, void *data); + + /** + * Create an Eet_Key needed for signing an eet file. + * + * The certificate should provide the public that match the private key. + * No verification is done to ensure that. + * + * @since 2.0.0 + */ + EAPI Eet_Key* eet_identity_open(const char *certificate_file, const char *private_key_file, Eet_Key_Password_Callback cb); + + /** + * Close and release all ressource used by an Eet_Key. + * An reference counter prevent it from being freed until all file using it are + * also closed. + * + * @since 2.0.0 + */ + EAPI void eet_identity_close(Eet_Key *key); + + /** + * Set a key to sign a file + * + * @since 2.0.0 + */ + EAPI Eet_Error eet_identity_set(Eet_File *ef, Eet_Key *key); + + /** + * Display both private and public key of an Eet_Key. + * + * @since 2.0.0 + */ + EAPI void eet_identity_print(Eet_Key *key, FILE *out); + + /** + * Get the x509 der certificate associated with an Eet_File. Will return NULL + * if the file is not signed. + * + * @since 2.0.0 + */ + EAPI const void *eet_identity_x509(Eet_File *ef, int *der_length); + + /** + * Display the x509 der certificate to out. + * + * @since 2.0.0 + */ + EAPI void eet_identity_certificate_print(const unsigned char *certificate, int der_length, FILE *out); /** * Return a handle to the shared string dictionary of the Eet file diff --git a/legacy/eet/src/lib/Eet_private.h b/legacy/eet/src/lib/Eet_private.h index 7160783e98..57da2a4744 100644 --- a/legacy/eet/src/lib/Eet_private.h +++ b/legacy/eet/src/lib/Eet_private.h @@ -12,6 +12,14 @@ # endif #endif +#include "config.h" + +#ifdef HAVE_OPENSSL +#include +#include +#include +#endif + typedef struct _Eet_String Eet_String; struct _Eet_String @@ -53,6 +61,15 @@ struct _Eet_Dictionary const char *end; }; +struct _Eet_Key +{ + int references; +#ifdef HAVE_SIGNATURE + X509 *certificate; + EVP_PKEY *private_key; +#endif +}; + Eet_Dictionary *eet_dictionary_add(void); void eet_dictionary_free(Eet_Dictionary *ed); int eet_dictionary_string_add(Eet_Dictionary *ed, const char *string); @@ -66,6 +83,15 @@ int _eet_hash_gen(const char *key, int hash_size); int _eet_string_to_double_convert(const char *src, long long *m, long *e); void _eet_double_to_string_convert(char des[128], double d); +const void* eet_identity_check(const void *data_base, unsigned int data_length, + const void *signature_base, unsigned int signature_length, + int *x509_length); +Eet_Error eet_cypher(void *data, unsigned int size, const char *key, unsigned int length); +Eet_Error eet_decypher(void *data, unsigned int size, const char *key, unsigned int length); +Eet_Error eet_identity_sign(FILE *fp, Eet_Key *key); +void eet_identity_unref(Eet_Key *key); +void eet_identity_ref(Eet_Key *key); + #ifndef PATH_MAX #define PATH_MAX 4096 #endif diff --git a/legacy/eet/src/lib/Makefile.am b/legacy/eet/src/lib/Makefile.am index 0214fa3e77..7055ffd7a2 100644 --- a/legacy/eet/src/lib/Makefile.am +++ b/legacy/eet/src/lib/Makefile.am @@ -8,7 +8,8 @@ AM_CPPFLAGS = \ -DPACKAGE_LIB_DIR=\"$(libdir)\" \ -DPACKAGE_DATA_DIR=\"$(datadir)/$(PACKAGE)\" \ @EVIL_CFLAGS@ \ -@COVERAGE_CFLAGS@ +@COVERAGE_CFLAGS@ \ +@OPENSSL_CFLAGS@ include_HEADERS = Eet.h @@ -18,6 +19,7 @@ libeet_la_SOURCES = \ eet_lib.c \ eet_data.c \ eet_image.c \ +eet_cypher.c \ eet_dictionary.c \ eet_utils.c diff --git a/legacy/eet/src/lib/eet_cypher.c b/legacy/eet/src/lib/eet_cypher.c new file mode 100644 index 0000000000..dcaab55357 --- /dev/null +++ b/legacy/eet/src/lib/eet_cypher.c @@ -0,0 +1,335 @@ +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_SIGNATURE +# include +# include +# include +# include +# include +# include +#endif + +#include "Eet.h" +#include "Eet_private.h" + +#define EET_MAGIC_SIGN 0x1ee74271 + +EAPI Eet_Key* +eet_identity_open(const char *certificate_file, const char *private_key_file, Eet_Key_Password_Callback cb) +{ +#ifdef HAVE_SIGNATURE + EVP_PKEY *pkey = NULL; + X509 *cert = NULL; + Eet_Key *key; + FILE *fp; + + /* Load the X509 certificate in memory. */ + fp = fopen(certificate_file, "r"); + if (!fp) return NULL; + cert = PEM_read_X509(fp, NULL, NULL, NULL); + fclose(fp); + if (!cert) return NULL; + + /* Check the presence of the public key. Just in case. */ + pkey = X509_get_pubkey(cert); + if (!pkey) goto on_error; + + /* Load the private key in memory. */ + fp = fopen(private_key_file, "r"); + if (!fp) goto on_error; + pkey = PEM_read_PrivateKey(fp, NULL, cb, NULL); + fclose(fp); + if (!pkey) goto on_error; + + key = malloc(sizeof(Eet_Key)); + if (!key) goto on_error; + + key->references = 1; + key->certificate = cert; + key->private_key = pkey; + + return key; + + on_error: + if (cert) X509_free(cert); + if (pkey) EVP_PKEY_free(pkey); +#endif + return NULL; +} + +EAPI void +eet_identity_print(Eet_Key *key, FILE *out) +{ +#ifdef HAVE_SIGNATURE + RSA *rsa; + DSA *dsa; + DH *dh; + + if (!key) return ; + + rsa = EVP_PKEY_get1_RSA(key->private_key); + if (rsa) + { + fprintf(out, "Private key (RSA) :\n"); + RSA_print_fp(out, rsa, 0); + } + + dsa = EVP_PKEY_get1_DSA(key->private_key); + if (dsa) + { + fprintf(out, "Private key (DSA) :\n"); + DSA_print_fp(out, dsa, 0); + } + + dh = EVP_PKEY_get1_DH(key->private_key); + if (dh) + { + fprintf(out, "Private key (DH) :\n"); + DHparams_print_fp(out, dh); + } + + fprintf(out, "Public certificate :\n"); + X509_print_fp(out, key->certificate); +#else + fprintf(out, "You need to compile signature support in EET.\n"); +#endif +} + +EAPI void +eet_identity_close(Eet_Key *key) +{ +#ifdef HAVE_SIGNATURE + if (key->references > 0) return ; + + X509_free(key->certificate); + EVP_PKEY_free(key->private_key); + free(key); +#endif +} + +void +eet_identity_ref(Eet_Key *key) +{ + if (key == NULL) return ; + key->references++; +} + +void +eet_identity_unref(Eet_Key *key) +{ + if (key == NULL) return ; + key->references--; + eet_identity_close(key); +} + +Eet_Error +eet_identity_sign(FILE *fp, Eet_Key *key) +{ +#ifdef HAVE_SIGNATURE + unsigned char *x509_der = NULL; + void *sign = NULL; + void *data; + int head[3]; + EVP_MD_CTX md_ctx; + struct stat st_buf; + Eet_Error err = EET_ERROR_NONE; + int sign_length; + int x509_length; + int fd; + + /* A few check and flush pending write. */ + if (!fp + || !key + || !key->certificate + || !key->private_key) + return EET_ERROR_BAD_OBJECT; + + /* Get the file size. */ + fd = fileno(fp); + if (fd < 0) return EET_ERROR_BAD_OBJECT; + if (fstat(fd, &st_buf) < 0) return EET_ERROR_MMAP_FAILED; + + /* Map the file in memory. */ + data = mmap(NULL, st_buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (data == MAP_FAILED) return EET_ERROR_MMAP_FAILED; + + sign_length = EVP_PKEY_size(key->private_key); + sign = malloc(sign_length); + if (sign == NULL) + { + err = EET_ERROR_OUT_OF_MEMORY; + goto on_error; + } + + /* Do the signature. */ + EVP_SignInit(&md_ctx, EVP_sha1()); + EVP_SignUpdate (&md_ctx, data, st_buf.st_size); + err = EVP_SignFinal (&md_ctx, sign, &sign_length, key->private_key); + if (err != 1) + { + ERR_print_errors_fp(stdout); + err = EET_ERROR_SIGNATURE_FAILED; + goto on_error; + } + + /* Give me the der (binary form for X509). */ + x509_length = i2d_X509(key->certificate, &x509_der); + if (x509_length < 0) + { + ERR_print_errors_fp(stdout); + err = EET_ERROR_X509_ENCODING_FAILED; + goto on_error; + } + + /* Append the signature at the end of the file. */ + head[0] = (int) htonl ((unsigned int) EET_MAGIC_SIGN); + head[1] = (int) htonl ((unsigned int) sign_length); + head[2] = (int) htonl ((unsigned int) x509_length); + + if (fwrite(head, sizeof(head), 1, fp) != 1) + { + err = EET_ERROR_WRITE_ERROR; + goto on_error; + } + if (fwrite(sign, sign_length, 1, fp) != 1) + { + err = EET_ERROR_WRITE_ERROR; + goto on_error; + } + if (fwrite(x509_der, x509_length, 1, fp) != 1) + { + err = EET_ERROR_WRITE_ERROR; + goto on_error; + } + + on_error: + if (x509_der) OPENSSL_free(x509_der); + if (sign != NULL) free(sign); + munmap(data, st_buf.st_size); + return err; +#else + return EET_ERROR_NOT_IMPLEMENTED; +#endif +} + +const void* +eet_identity_check(const void *data_base, unsigned int data_length, + const void *signature_base, unsigned int signature_length, + int *x509_length) +{ +#ifdef HAVE_SIGNATURE + const int *header = signature_base; + const unsigned char *sign; + const unsigned char *cert_der; + const unsigned char *tmp; + EVP_PKEY *pkey; + X509 *x509; + EVP_MD_CTX md_ctx; + int sign_length; + int cert_length; + int magic; + int err; + + if (signature_length < sizeof(int) * 3) return NULL; + + magic = ntohl(header[0]); + sign_length = ntohl(header[1]); + cert_length = ntohl(header[2]); + + if (magic != EET_MAGIC_SIGN) return NULL; + if (sign_length + cert_length + sizeof(int) * 3 > signature_length) return NULL; + + sign = signature_base + sizeof(int) * 3; + cert_der = sign + sign_length; + + /* Strange but d2i_X509 seems to put 0 all over the place. */ + tmp = alloca(cert_length); + memcpy((char*) tmp, cert_der, cert_length); + x509 = d2i_X509(NULL, &tmp, cert_length); + if (x509 == NULL) return NULL; + + /* Get public key - eay */ + pkey=X509_get_pubkey(x509); + if (pkey == NULL) + { + X509_free(x509); + return NULL; + } + + /* Verify the signature */ + EVP_VerifyInit(&md_ctx, EVP_sha1()); + EVP_VerifyUpdate(&md_ctx, data_base, data_length); + err = EVP_VerifyFinal(&md_ctx, sign, sign_length, pkey); + + X509_free(x509); + EVP_PKEY_free(pkey); + + if (err != 1) + return NULL; + + if (x509_length) *x509_length = cert_length; + return cert_der; +#else + return NULL; +#endif +} + +EAPI void +eet_identity_certificate_print(const unsigned char *certificate, int der_length, FILE *out) +{ +#ifdef HAVE_SIGNATURE + const unsigned char *tmp; + X509 *x509; + + if (certificate == NULL + || out == NULL + || der_length <= 0) + { + fprintf(out, "No certificate provided.\n"); + return ; + } + + /* Strange but d2i_X509 seems to put 0 all over the place. */ + tmp = alloca(der_length); + memcpy((char*) tmp, certificate, der_length); + x509 = d2i_X509(NULL, &tmp, der_length); + if (x509 == NULL) + { + fprintf(out, "Not a valid certificate.\n"); + return ; + } + + fprintf(out, "Public certificate :\n"); + X509_print_fp(out, x509); + + X509_free(x509); +#else + fprintf(out, "You need to compile signature support in EET.\n"); +#endif +} + +Eet_Error +eet_cypher(void *data, unsigned int size, const char *key, unsigned int length) +{ +#ifdef HAVE_CYPHER +#else + return EET_ERROR_NOT_IMPLEMENTED; +#endif +} + +Eet_Error +eet_decypher(void *data, unsigned int size, const char *key, unsigned int length) +{ +#ifdef HAVE_CYPHER +#else + return EET_ERROR_NOT_IMPLEMENTED; +#endif +} diff --git a/legacy/eet/src/lib/eet_lib.c b/legacy/eet/src/lib/eet_lib.c index 9d0be1ce38..76e60dfce1 100644 --- a/legacy/eet/src/lib/eet_lib.c +++ b/legacy/eet/src/lib/eet_lib.c @@ -69,14 +69,17 @@ struct _Eet_File FILE *fp; FILE *readfp; Eet_File_Header *header; - const unsigned char *data; Eet_Dictionary *ed; + Eet_Key *key; + const unsigned char *data; + const void *x509_der; int magic; int references; Eet_File_Mode mode; int data_size; + int x509_length; time_t mtime; unsigned char writes_pending : 1; @@ -158,6 +161,11 @@ struct } dictionary[num_dictionary_entries]; /* now start the string stream. */ /* and right after them the data stream. */ +int magic_sign; /* Optional, only if the eet file is signed. */ +int signature_length; /* Signature length. */ +int x509_length; /* Public certificate that signed the file. */ +char signature[signature_length]; /* The signature. */ +char x509[x509_length]; /* The public certificate. */ #endif #define EET_FILE2_HEADER_COUNT 3 @@ -379,8 +387,11 @@ eet_flush2(Eet_File *ef) return EET_ERROR_NONE; if (ef->mode == EET_FILE_MODE_READ_WRITE && ef->fp == NULL) { + int fd; + unlink(ef->path); - ef->fp = fopen(ef->path, "wb"); + fd = open(file, O_CREAT | O_TRUNC | O_RDWR, S_IRUSR | S_IWUSR); + ef->fp = fdopen(fd, "wb"); if (!ef->fp) return EET_ERROR_NOT_WRITABLE; fcntl(fileno(ef->fp), F_SETFD, FD_CLOEXEC); } @@ -516,6 +527,17 @@ eet_flush2(Eet_File *ef) } } + /* flush all write to the file. */ + fflush(ef->fp); + + /* append signature if required */ + if (ef->key) + { + error = eet_identity_sign(ef->fp, ef->key); + if (error != EET_ERROR_NONE) + goto sign_error; + } + /* no more writes pending */ ef->writes_pending = 0; @@ -651,6 +673,7 @@ eet_flush(Eet_File *ef) ef->fp = NULL; return EET_ERROR_WRITE_ERROR; } + sign_error: fclose(ef->fp); ef->fp = NULL; return EET_ERROR_WRITE_ERROR; @@ -660,6 +683,19 @@ eet_flush(Eet_File *ef) EAPI int eet_init(void) { +#ifdef HAVE_OPENSSL + /* Just load the crypto library error strings, + * SSL_load_error_strings() loads the crypto AND the SSL ones */ + /* SSL_load_error_strings();*/ + static int call_once = 0; + + if (call_once == 0) + { + call_once = 1; + ERR_load_crypto_strings(); + } + +#endif return ++eet_initcount; } @@ -738,6 +774,7 @@ eet_internal_read2(Eet_File *ef) int bytes_directory_entries; int num_dictionary_entries; int bytes_dictionary_entries; + int signature_base_offset; int i; index += sizeof(int); @@ -787,6 +824,8 @@ eet_internal_read2(Eet_File *ef) if (eet_test_close(!ef->header->directory->nodes, ef)) return NULL; + signature_base_offset = 0; + /* actually read the directory block - all of it, into ram */ for (i = 0; i < num_directory_entries; ++i) { @@ -850,6 +889,10 @@ eet_internal_read2(Eet_File *ef) if (efn->data) memcpy(efn->data, ef->data + efn->offset, efn->size); } + + /* compute the possible position of a signature */ + if (signature_base_offset < efn->offset + efn->size) + signature_base_offset = efn->offset + efn->size; } ef->ed = NULL; @@ -906,9 +949,35 @@ eet_internal_read2(Eet_File *ef) ef->ed->all[j].hash = hash; if (ef->ed->all[j].prev == -1) ef->ed->hash[hash] = j; + + /* compute the possible position of a signature */ + if (signature_base_offset < offset + ef->ed->all[j].len) + signature_base_offset = offset + ef->ed->all[j].len; } } + /* Check if the file is signed */ + ef->x509_der = NULL; + ef->x509_length = 0; + if (signature_base_offset < ef->data_size) + { +#ifdef HAVE_SIGNATURE + const unsigned char *buffer = ((const unsigned char*) ef->data) + signature_base_offset; + ef->x509_der = eet_identity_check(ef->data, signature_base_offset, + buffer, ef->data_size - signature_base_offset, + &ef->x509_length); + + if (ef->x509_der == NULL) + { + ef->delete_me_now = 1; + eet_close(ef); + return NULL; + } +#else + fprintf(stderr, "This file could be signed but you didn't compile the necessary code to check the signature.\n"); +#endif + } + return ef; } @@ -1120,6 +1189,7 @@ eet_memopen_read(const void *data, size_t size) ef->ed = NULL; ef->path = NULL; + ef->key = NULL; ef->magic = EET_MAGIC_FILE; ef->references = 1; ef->mode = EET_FILE_MODE_READ; @@ -1229,6 +1299,7 @@ eet_open(const char *file, Eet_File_Mode mode) /* fill some of the members */ ef->fp = fp; + ef->key = NULL; ef->readfp = NULL; ef->path = ((char *)ef) + sizeof(Eet_File); memcpy(ef->path, file, file_len); @@ -1297,6 +1368,32 @@ eet_mode_get(Eet_File *ef) return ef->mode; } +EAPI const void * +eet_identity_x509(Eet_File *ef, int *der_length) +{ + if (!ef->x509_der) return NULL; + + if (der_length) *der_length = ef->x509_length; + return ef->x509_der; +} + +EAPI Eet_Error +eet_identity_set(Eet_File *ef, Eet_Key *key) +{ + Eet_Key *tmp = ef->key; + + if (!ef) return EET_ERROR_BAD_OBJECT; + + ef->key = key; + eet_identity_ref(ef->key); + eet_identity_unref(tmp); + + /* flags that writes are pending */ + ef->writes_pending = 1; + + return EET_ERROR_NONE; +} + EAPI Eet_Error eet_close(Eet_File *ef) { @@ -1312,6 +1409,9 @@ eet_close(Eet_File *ef) /* flush any writes */ err = eet_flush2(ef); + eet_identity_unref(ef->key); + ef->key = NULL; + /* if not urgent to delete it - dont free it - leave it in cache */ if ((!ef->delete_me_now) && (ef->mode == EET_FILE_MODE_READ)) return EET_ERROR_NONE; diff --git a/legacy/eet/src/tests/cert.pem b/legacy/eet/src/tests/cert.pem new file mode 100644 index 0000000000..3265462d7b --- /dev/null +++ b/legacy/eet/src/tests/cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDmTCCAwKgAwIBAgIJAIKWPcLUT5FAMA0GCSqGSIb3DQEBBQUAMIGQMQswCQYD +VQQGEwJGUjEWMBQGA1UECBMNSWxlLURlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMx +FjAUBgNVBAoTDUVubGlnaHRlbm1lbnQxDjAMBgNVBAsTBVRlc3RzMQ0wCwYDVQQD +EwRCQUlMMSIwIAYJKoZIhvcNAQkBFhNjZWRyaWMuYmFpbEBmcmVlLmZyMB4XDTA4 +MDczMDEzNDU1OVoXDTA5MDczMDEzNDU1OVowgZAxCzAJBgNVBAYTAkZSMRYwFAYD +VQQIEw1JbGUtRGUtRnJhbmNlMQ4wDAYDVQQHEwVQYXJpczEWMBQGA1UEChMNRW5s +aWdodGVubWVudDEOMAwGA1UECxMFVGVzdHMxDTALBgNVBAMTBEJBSUwxIjAgBgkq +hkiG9w0BCQEWE2NlZHJpYy5iYWlsQGZyZWUuZnIwgZ8wDQYJKoZIhvcNAQEBBQAD +gY0AMIGJAoGBAMiE486eROKePG0/639D4XTTDR9XSRWp1xqZzq7P+jjWRFbZ/MWV +IVzkc4MRm83UOolbPj76LjM10cseaVAhK7G9CHp2dur4alWvdCXPH5Q+LPOFS9gM +x0Jz9EZeHHOHZKLyJdKSmot+zluwJTLe081RRUwzNKct6JrVVG/7SmITAgMBAAGj +gfgwgfUwHQYDVR0OBBYEFEFar6doT5ImL2rf0rJX7EYQqtYQMIHFBgNVHSMEgb0w +gbqAFEFar6doT5ImL2rf0rJX7EYQqtYQoYGWpIGTMIGQMQswCQYDVQQGEwJGUjEW +MBQGA1UECBMNSWxlLURlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxFjAUBgNVBAoT +DUVubGlnaHRlbm1lbnQxDjAMBgNVBAsTBVRlc3RzMQ0wCwYDVQQDEwRCQUlMMSIw +IAYJKoZIhvcNAQkBFhNjZWRyaWMuYmFpbEBmcmVlLmZyggkAgpY9wtRPkUAwDAYD +VR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQCpZJhk8BgQh0foiMkOwOMKvObq +GxAzqjbr7iU9tEvJgwukCBv59ndBM0B5l5ybQdIYWQJOfZE1HTvB60swZMwqap9X +5QXgewymuXiVk+roVh34wg8Pg8F588G2BtLIoujY/gN3WJQR7YPD34iTPc4koV+A +4vs6nmL6wtW21+hsaw== +-----END CERTIFICATE----- diff --git a/legacy/eet/src/tests/eet_suite.c b/legacy/eet/src/tests/eet_suite.c index 003dfa5c75..c52b15c950 100644 --- a/legacy/eet/src/tests/eet_suite.c +++ b/legacy/eet/src/tests/eet_suite.c @@ -1,10 +1,17 @@ +#include +#include #include #include #include #include +#include #include +#ifdef HAVE_CONFIG_H +# include +#endif + #include "eet_suite.h" START_TEST(eet_test_init) @@ -1146,6 +1153,77 @@ START_TEST(eet_small_image) } END_TEST +START_TEST(eet_identity_simple) +{ + const char *buffer = "Here is a string of data to save !"; + const void *tmp; + Eet_File *ef; + Eet_Key *k; + char *test; + char *file = strdup("/tmp/eet_suite_testXXXXXX"); + int size; + int fd; + + eet_init(); + + mktemp(file); + chdir("src/tests"); + + /* Sign an eet file. */ + ef = eet_open(file, EET_FILE_MODE_WRITE); + fail_if(!ef); + + fail_if(!eet_write(ef, "keys/tests", buffer, strlen(buffer) + 1, 0)); + + k = eet_identity_open("cert.pem", "key.pem", NULL); + fail_if(!k); + + fail_if(eet_identity_set(ef, k) != EET_ERROR_NONE); + + eet_close(ef); + + /* Open a signed file. */ + ef = eet_open(file, EET_FILE_MODE_READ); + fail_if(!ef); + + test = eet_read(ef, "keys/tests", &size); + fail_if(!test); + fail_if(size != strlen(buffer) + 1); + + fail_if(memcmp(test, buffer, strlen(buffer) + 1) != 0); + + tmp = eet_identity_x509(ef, &size); + fail_if(tmp == NULL); + + eet_close(ef); + + /* As we are changing file contain in less than 1s, this could get unnoticed + by eet cache system. */ + eet_clearcache(); + + /* Corrupting the file. */ + fd = open(file, O_WRONLY); + fail_if(fd < 0); + + fail_if(lseek(fd, 200, SEEK_SET) != 200); + fail_if(write(fd, "42", 2) != 2); + fail_if(lseek(fd, 50, SEEK_SET) != 50); + fail_if(write(fd, "42", 2) != 2); + fail_if(lseek(fd, 88, SEEK_SET) != 88); + fail_if(write(fd, "42", 2) != 2); + + close(fd); + + /* Attempt to open a modified file. */ + ef = eet_open(file, EET_FILE_MODE_READ); + fail_if(ef); + + fail_if(unlink(file) != 0); + + eet_shutdown(); +} +END_TEST + Suite * eet_suite(void) { @@ -1175,6 +1253,12 @@ eet_suite(void) tcase_add_test(tc, eet_small_image); suite_add_tcase(s, tc); +#ifdef HAVE_SIGNATURE + tc = tcase_create("Eet Identity"); + tcase_add_test(tc, eet_identity_simple); + suite_add_tcase(s, tc); +#endif + return s; } diff --git a/legacy/eet/src/tests/key.pem b/legacy/eet/src/tests/key.pem new file mode 100644 index 0000000000..74763ca8c8 --- /dev/null +++ b/legacy/eet/src/tests/key.pem @@ -0,0 +1,15 @@ +-----BEGIN RSA PRIVATE KEY----- +MIICXAIBAAKBgQDIhOPOnkTinjxtP+t/Q+F00w0fV0kVqdcamc6uz/o41kRW2fzF +lSFc5HODEZvN1DqJWz4++i4zNdHLHmlQISuxvQh6dnbq+GpVr3Qlzx+UPizzhUvY +DMdCc/RGXhxzh2Si8iXSkpqLfs5bsCUy3tPNUUVMMzSnLeia1VRv+0piEwIDAQAB +AoGAfLLHyNJ8HEIzae16UmawaqplWrw5YxOABbbo5aXJAledoDVoEKexW8dmXngw +4Eu/K3RmvVtwJ8CsexiqfX5jYMU+YKRbww6Vqr/punIUhiEHVarHMFKG9yo14qSa +z2xPgXvC5p7/Rhci+rAUp36S5kIHch5sLhEEcJayymyzDyECQQD/5B3JdpcovrSI ++nyZ8Iub2+I3f3uox6m1DKxHead26ICoIr7VCnPV5J1gLIB2MofVCbKhmy4PNi5a +0QdvazJfAkEAyJq9Y+9SQ4sCOVDrFklJxhXuZE4WbnR32XsBdnQ9dauo0E2vDVkv +6mHnzMWroTjLv4hH5nufE5NvMo8PNGB0zQJAFOKkf737JmsyRv/Szamxa14t/4Ob +LzJkqo9HPGo0feMKJS74zmCVBb8sDR50ubD0HzI0bzZAMyOj8uuepLxmFwJAH+RR +5bhfeLN52AjgRvvBycckzjeH42mKwD2I/v794l43CV7ATLv4HSgRhQGMBqaT5dBR +tffDU4Zl8EDEJwyKpQJBAJ2NNacURTyavU699QJOIdGAsA4KXici8H3PuuWMtHLR +RKdPFeaCRn+9p7Tglf0rH9hUGOpUXHYD3+ECt6gnVDc= +-----END RSA PRIVATE KEY-----