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-----