aheinecke@4: #include "listutil.h" aheinecke@4: aheinecke@4: #include aheinecke@4: #include aheinecke@4: #include aheinecke@4: #include aheinecke@4: #include aheinecke@4: #include aheinecke@4: #include aheinecke@7: #include aheinecke@4: aheinecke@28: #ifdef RELEASE aheinecke@28: #include "pubkey-release.h" aheinecke@28: #else aheinecke@28: #include "pubkey-test.h" aheinecke@28: #endif aheinecke@28: aheinecke@28: #pragma GCC diagnostic ignored "-Wconversion" aheinecke@28: /* Polarssl mh.h contains a conversion which gcc warns about */ aheinecke@28: #include aheinecke@31: #include aheinecke@31: #include aheinecke@28: #pragma GCC diagnostic pop aheinecke@28: aheinecke@68: #define MAX_FILESIZE MAX_LINE_LENGTH * MAX_LINES aheinecke@4: aheinecke@31: /** aheinecke@31: * @brief Read a file into memory. aheinecke@31: * aheinecke@31: * The caller needs to free data aheinecke@31: * aheinecke@31: * @param[in] fileName Name of the file. aheinecke@31: * @param[out] data the file content aheinecke@31: * @param[out] size size in bytes of the file content. aheinecke@31: * @param[in] max_size the maximum amount of bytes to read. aheinecke@31: * aheinecke@31: * @return 0 on success an error code otherwise. aheinecke@31: */ aheinecke@31: #define READ_FILE_UNREADABLE -1 aheinecke@31: #define READ_FILE_TOO_LARGE -2 aheinecke@31: #define READ_FILE_NO_MEMORY -3 aheinecke@31: #define READ_FILE_READ_FAILED -4 aheinecke@86: #define READ_FILE_INVALID_CALL -5 aheinecke@31: static int read_file(const char *file_name, char **data, size_t *size, aheinecke@31: const size_t max_size) aheinecke@4: { aheinecke@31: FILE *f; aheinecke@31: long file_size; aheinecke@4: aheinecke@86: if (!file_name || !data || !size || !max_size) { aheinecke@86: return READ_FILE_INVALID_CALL; aheinecke@86: } aheinecke@86: aheinecke@31: f = fopen(file_name, "rb"); aheinecke@31: if (f == NULL) aheinecke@31: return READ_FILE_UNREADABLE; aheinecke@4: aheinecke@31: fseek(f, 0, SEEK_END); aheinecke@31: file_size = ftell(f); aheinecke@89: if (file_size <= 0){ aheinecke@31: fclose(f); aheinecke@31: return READ_FILE_UNREADABLE; aheinecke@4: } aheinecke@4: aheinecke@31: fseek(f, 0, SEEK_SET); aheinecke@4: aheinecke@31: if (file_size + 1 == 0) { aheinecke@38: fclose(f); aheinecke@31: return READ_FILE_TOO_LARGE; aheinecke@31: } aheinecke@31: *size = (size_t) file_size; aheinecke@4: aheinecke@38: if (*size > max_size) { aheinecke@38: fclose(f); aheinecke@31: return READ_FILE_TOO_LARGE; aheinecke@38: } aheinecke@31: aheinecke@31: *data = (char *) malloc( *size + 1 ); bernhard@61: if (*data == NULL) { aheinecke@31: fclose(f); aheinecke@31: return READ_FILE_NO_MEMORY; aheinecke@4: } aheinecke@4: aheinecke@31: if (fread(*data, 1, *size, f) != *size) { bernhard@66: free(*data); aheinecke@31: fclose(f); aheinecke@31: return READ_FILE_READ_FAILED; aheinecke@4: } aheinecke@4: aheinecke@31: fclose(f); aheinecke@4: aheinecke@31: (*data)[*size] = '\0'; aheinecke@4: aheinecke@31: return 0; aheinecke@4: } aheinecke@4: aheinecke@68: int verify_list(const char *data, const size_t size) aheinecke@4: { aheinecke@28: int ret = -1; aheinecke@28: pk_context pub_key_ctx; aheinecke@31: char *p; aheinecke@31: /* Fixed key size of 3072 implies the sizes*/ aheinecke@31: const size_t sig_b64_size = 512; aheinecke@31: size_t sig_size = 384; aheinecke@31: aheinecke@31: char signature_b64[sig_b64_size + 1]; aheinecke@31: unsigned char signature[sig_size]; aheinecke@31: /* Hash algroithm is sha256 */ aheinecke@31: unsigned char hash[32]; aheinecke@31: aheinecke@31: /* Fetch the signature from the first line od data */ aheinecke@31: p = strchr(data, '\r'); aheinecke@31: if (p == 0 || (unsigned int)(p - (data + 2)) != sig_b64_size) { aheinecke@40: /* printf("Invalid data. Signature might be too long.\n"); */ aheinecke@31: return -1; aheinecke@31: } aheinecke@31: strncpy(signature_b64, data + 2, sig_b64_size); aheinecke@31: signature_b64[sig_b64_size] = '\0'; aheinecke@31: aheinecke@31: ret = base64_decode(signature, &sig_size, aheinecke@31: (unsigned char *)signature_b64, sig_b64_size); aheinecke@31: aheinecke@31: if (ret != 0 || sig_size != 384) { aheinecke@40: /* printf("failed to decode signature\n"); */ aheinecke@31: return -1; aheinecke@31: } aheinecke@31: aheinecke@31: /* Hash is calculated over the data without the first line. aheinecke@31: * linebreaks are \r\n so the first char of the new line is aheinecke@31: * p+2 */ aheinecke@31: p += 2; aheinecke@31: /* Size of the data to hash is the size - signature line aheinecke@31: * signature line is sig_b64_size - "S:" and - "\r\n" so -4*/ aheinecke@31: sha256((unsigned char *)p, size - sig_b64_size - 4, hash, 0); aheinecke@28: aheinecke@28: pk_init(&pub_key_ctx); aheinecke@31: #if 0 aheinecke@31: { aheinecke@31: int i; aheinecke@31: FILE *foo = fopen("/tmp/testdump", "w"); aheinecke@31: FILE *foo2 = fopen("/tmp/rawdump", "w"); aheinecke@31: for (i=0; i< (int)(size - sig_b64_size - 2); i++) aheinecke@31: fprintf (foo, "%c", p[i]); aheinecke@31: for (i=0; i< (int)(size); i++) aheinecke@31: fprintf (foo2, "%c", data[i]); aheinecke@31: fclose(foo); aheinecke@31: printf ("Hash: \n"); aheinecke@31: for (i=0; i<32; i++) { aheinecke@31: printf ("%x", hash[i]); aheinecke@31: } aheinecke@31: printf("\n"); aheinecke@31: } aheinecke@31: #endif aheinecke@28: aheinecke@31: ret = pk_parse_public_key(&pub_key_ctx, public_key_pem, aheinecke@31: public_key_pem_size); aheinecke@28: if (ret != 0) { aheinecke@28: printf("pk_parse_public_key failed with -0x%04x\n\n", -ret); aheinecke@31: pk_free(&pub_key_ctx); aheinecke@31: return ret; aheinecke@28: } aheinecke@28: aheinecke@31: ret = pk_verify(&pub_key_ctx, POLARSSL_MD_SHA256, hash, 0, aheinecke@31: signature, sig_size); aheinecke@31: aheinecke@31: if (ret != 0) { aheinecke@31: printf("pk_verify failed with -0x%04x\n\n", -ret); aheinecke@31: } aheinecke@28: pk_free(&pub_key_ctx); aheinecke@31: aheinecke@28: return ret; aheinecke@28: } aheinecke@28: aheinecke@28: list_status_t read_and_verify_list(const char *file_name, char **data, aheinecke@28: size_t *size) aheinecke@28: { aheinecke@4: list_status_t retval = UnknownError; aheinecke@7: *data = NULL; aheinecke@7: *size = 0; aheinecke@31: int ret = 0; aheinecke@4: aheinecke@31: ret = read_file(file_name, data, size, MAX_FILESIZE); aheinecke@4: aheinecke@40: /* printf ("Ret: %i \n", ret); */ aheinecke@31: if (ret != 0) { aheinecke@31: if (ret == READ_FILE_TOO_LARGE) { aheinecke@31: return TooLarge; aheinecke@31: } aheinecke@31: if (ret == READ_FILE_UNREADABLE) { bernhard@66: /* TODO: work with errno ? */ aheinecke@31: return SeekFailed; aheinecke@31: } aheinecke@31: if (ret == READ_FILE_READ_FAILED) { bernhard@66: /* TODO: work with ferror() or feof() ? */ aheinecke@31: return ReadFailed; aheinecke@31: } aheinecke@4: return UnknownError; aheinecke@4: } aheinecke@4: aheinecke@31: if (!*data || !*size) { aheinecke@40: /* File is probably empty */ aheinecke@31: return UnknownError; aheinecke@4: } aheinecke@4: aheinecke@31: if (**data != 'S') { aheinecke@31: retval = InvalidFormat; aheinecke@31: } else { aheinecke@31: ret = verify_list (*data, *size); aheinecke@31: if (ret == 0) { aheinecke@31: /* Hooray */ aheinecke@31: return Valid; aheinecke@31: } aheinecke@31: if (ret == -1) { aheinecke@31: /* our error */ aheinecke@31: retval = InvalidFormat; aheinecke@31: } else { aheinecke@92: retval = InvalidSignature; aheinecke@31: } aheinecke@31: } aheinecke@9: aheinecke@7: if (retval != Valid && *data) { aheinecke@7: free(*data); aheinecke@7: *data = NULL; aheinecke@4: *size = 0; aheinecke@4: } aheinecke@4: return retval; aheinecke@4: } aheinecke@4: aheinecke@68: char **get_certs_to_remove(const char *data, const size_t size) { aheinecke@68: aheinecke@68: /* TODO */ aheinecke@68: if (!data || !size) { aheinecke@68: printf ("Invalid call to get_certs_to_remove \n"); aheinecke@68: return NULL; aheinecke@68: } aheinecke@68: return NULL; aheinecke@68: } aheinecke@68: aheinecke@68: char **get_certs_to_install(const char *data, const size_t size) { aheinecke@68: aheinecke@68: /* TODO */ aheinecke@68: if (!data || !size) { aheinecke@68: printf ("Invalid call to get_certs_to_install \n"); aheinecke@68: return NULL; aheinecke@68: } aheinecke@68: return NULL; aheinecke@68: }