diff --git a/src/create_pdf.c b/src/create_pdf.c index 28cd8ab0..f6453c32 100644 --- a/src/create_pdf.c +++ b/src/create_pdf.c @@ -45,6 +45,12 @@ #include #include "conf.h" +/* OpenSSL Headers */ +#include +#include +#include +#include + #define text_size_data 10 struct pdf_doc* pdf; @@ -52,12 +58,17 @@ struct pdf_object* page; char model_header[50] = ""; /* Model text in the header */ char serial_header[30] = ""; /* Serial number text in the header */ -char barcode[100] = ""; /* Contents of the barcode, i.e model:serial */ +char barcode[100] = ""; /* Contents of the barcode, i.e., model:serial */ char pdf_footer[MAX_PDF_FOOTER_TEXT_LENGTH]; float height; float page_width; int status_icon; +/* Prototypes for new functions */ +int generate_key_and_certificate( EVP_PKEY** pkey, X509** x509 ); +int sign_pdf( const char* pdf_filename, EVP_PKEY* pkey, unsigned char** signature, size_t* signature_len ); +void add_signature_to_pdf( struct pdf_doc* pdf, kwipe_context_t* c, unsigned char* signature, size_t signature_len ); + int create_pdf( kwipe_context_t* ptr ) { extern kwipe_prng_t kwipe_twister; @@ -70,17 +81,14 @@ int create_pdf( kwipe_context_t* ptr ) extern config_t kwipe_cfg; extern char kwipe_config_file[]; - // char pdf_footer[MAX_PDF_FOOTER_TEXT_LENGTH]; kwipe_context_t* c; c = ptr; - // char model_header[50] = ""; /* Model text in the header */ - // char serial_header[30] = ""; /* Serial number text in the header */ + char device_size[100] = ""; /* Device size in the form xMB (xxxx bytes) */ - // char barcode[100] = ""; /* Contents of the barcode, i.e model:serial */ char verify[20] = ""; /* Verify option text */ - char blank[10] = ""; /* blanking pass, none, zeros, ones */ - char rounds[50] = ""; /* rounds ASCII numeric */ - char prng_type[50] = ""; /* type of prng, twister, isaac, isaac64 */ + char blank[10] = ""; /* Blanking pass: none, zeros, ones */ + char rounds[50] = ""; /* Rounds ASCII numeric */ + char prng_type[50] = ""; /* Type of PRNG */ char start_time_text[50] = ""; char end_time_text[50] = ""; char bytes_erased[50] = ""; @@ -90,11 +98,6 @@ int create_pdf( kwipe_context_t* ptr ) char throughput_txt[50] = ""; char bytes_percent_str[7] = ""; - // int status_icon; - - // float height; - // float page_width; - struct pdf_info info = { .creator = "https://github.com/PartialVolume/shredos.x86_64", .producer = "https://github.com/martijnvanbrummelen/kwipe", .title = "PDF Disk Erasure Certificate", @@ -105,28 +108,25 @@ int create_pdf( kwipe_context_t* ptr ) /* A pointer to the system time struct. */ struct tm* p; - /* variables used by libconfig */ + /* Variables used by libconfig */ config_setting_t* setting; const char *business_name, *business_address, *contact_name, *contact_phone, *op_tech_name, *customer_name, *customer_address, *customer_contact_name, *customer_contact_phone; - /* ------------------ */ - /* Initialise Various */ + /* Initialize variables */ /* Used to display correct icon on page 2 */ - status_icon = 0; // zero don't display icon, see header STATUS_ICON_.. + status_icon = 0; // zero means don't display icon, see header STATUS_ICON_... - // kwipe_log( NWIPE_LOG_NOTICE, "Create the PDF disk erasure certificate" ); - // struct pdf_doc* pdf = pdf_create( PDF_A4_WIDTH, PDF_A4_HEIGHT, &info ); pdf = pdf_create( PDF_A4_WIDTH, PDF_A4_HEIGHT, &info ); /* Create footer text string and append the version */ - snprintf( pdf_footer, sizeof( pdf_footer ), "Disc Erasure by NWIPE version %s", version_string ); + snprintf( pdf_footer, sizeof( pdf_footer ), "Disc Erasure by Nwipe version %s", version_string ); pdf_set_font( pdf, "Helvetica" ); struct pdf_object* page_1 = pdf_append_page( pdf ); - /* Obtain page page_width */ + /* Obtain page width */ page_width = pdf_page_width( page_1 ); /********************************************************************* @@ -151,16 +151,16 @@ int create_pdf( kwipe_context_t* ptr ) pdf_add_barcode( pdf, NULL, PDF_BARCODE_128A, 100, 790, 400, 25, barcode, PDF_BLACK ); /* ------------------------ */ - /* Organisation Information */ + /* Organization Information */ pdf_add_line( pdf, NULL, 50, 550, 550, 550, 1, PDF_GRAY ); - pdf_add_text( pdf, NULL, "Organisation Performing The Disk Erasure", 12, 50, 630, PDF_BLUE ); + pdf_add_text( pdf, NULL, "Organization Performing The Disk Erasure", 12, 50, 630, PDF_BLUE ); pdf_add_text( pdf, NULL, "Business Name:", 12, 60, 610, PDF_GRAY ); pdf_add_text( pdf, NULL, "Business Address:", 12, 60, 590, PDF_GRAY ); pdf_add_text( pdf, NULL, "Contact Name:", 12, 60, 570, PDF_GRAY ); pdf_add_text( pdf, NULL, "Contact Phone:", 12, 300, 570, PDF_GRAY ); - /* Obtain organisational details from kwipe.conf - See conf.c */ + /* Obtain organizational details from kwipe.conf - See conf.c */ setting = config_lookup( &kwipe_cfg, "Organisation_Details" ); if( setting != NULL ) { @@ -289,12 +289,12 @@ int create_pdf( kwipe_context_t* ptr ) } else { - /* If the calculared real max size as determined from HPA/DCO and libata data is larger than + /* If the calculated real max size as determined from HPA/DCO and libata data is larger than * or equal to the apparent device size then display that value in green. */ if( c->Calculated_real_max_size_in_bytes >= c->device_size ) { - /* displays the real max size of the disc from the DCO displayed in Green */ + /* Displays the real max size of the disk from the DCO displayed in Green */ snprintf( device_size, sizeof( device_size ), "%s, %lli bytes", @@ -312,8 +312,8 @@ int create_pdf( kwipe_context_t* ptr ) } else { - /* we are already here because c->DCO_reported_real_max_size < 1 so if HPA enabled then use the - * value we determine from whether HPA set, HPA real exist and if not assume libata's value*/ + /* We are already here because c->Calculated_real_max_size_in_bytes < 1 so if HPA enabled then use the + * value we determine from whether HPA set, HPA real exist and if not assume libata's value */ if( c->HPA_status == HPA_ENABLED ) { snprintf( device_size, @@ -339,7 +339,7 @@ int create_pdf( kwipe_context_t* ptr ) /* Erasure Details */ pdf_add_text( pdf, NULL, "Disk Erasure Details", 12, 50, 330, PDF_BLUE ); - /* start time */ + /* Start time */ pdf_add_text( pdf, NULL, "Start time:", 12, 60, 310, PDF_GRAY ); p = localtime( &c->start_time ); snprintf( start_time_text, @@ -355,7 +355,7 @@ int create_pdf( kwipe_context_t* ptr ) pdf_add_text( pdf, NULL, start_time_text, text_size_data, 120, 310, PDF_BLACK ); pdf_set_font( pdf, "Helvetica" ); - /* end time */ + /* End time */ pdf_add_text( pdf, NULL, "End time:", 12, 300, 310, PDF_GRAY ); p = localtime( &c->end_time ); snprintf( end_time_text, @@ -411,7 +411,7 @@ int create_pdf( kwipe_context_t* ptr ) { if( !strcmp( c->wipe_status_txt, "FAILED" ) ) { - // text shifted left slightly in ellipse due to extra character + // Text shifted left slightly in ellipse due to extra character pdf_add_text( pdf, NULL, c->wipe_status_txt, 12, 370, 290, PDF_RED ); // Display the red cross in the header @@ -440,7 +440,7 @@ int create_pdf( kwipe_context_t* ptr ) pdf_set_font( pdf, "Helvetica" ); /*********** - * prng type + * PRNG type */ pdf_add_text( pdf, NULL, "PRNG algorithm:", 12, 300, 270, PDF_GRAY ); if( kwipe_options.method == &kwipe_verify_one || kwipe_options.method == &kwipe_verify_zero @@ -454,37 +454,25 @@ int create_pdf( kwipe_context_t* ptr ) { snprintf( prng_type, sizeof( prng_type ), "Twister" ); } + else if( kwipe_options.prng == &kwipe_isaac ) + { + snprintf( prng_type, sizeof( prng_type ), "Isaac" ); + } + else if( kwipe_options.prng == &kwipe_isaac64 ) + { + snprintf( prng_type, sizeof( prng_type ), "Isaac64" ); + } + else if( kwipe_options.prng == &kwipe_add_lagg_fibonacci_prng ) + { + snprintf( prng_type, sizeof( prng_type ), "Fibonacci" ); + } + else if( kwipe_options.prng == &kwipe_xoroshiro256_prng ) + { + snprintf( prng_type, sizeof( prng_type ), "XORshiro256" ); + } else { - if( kwipe_options.prng == &kwipe_isaac ) - { - snprintf( prng_type, sizeof( prng_type ), "Isaac" ); - } - else - { - if( kwipe_options.prng == &kwipe_isaac64 ) - { - snprintf( prng_type, sizeof( prng_type ), "Isaac64" ); - } - else - { - if( kwipe_options.prng == &kwipe_add_lagg_fibonacci_prng ) - { - snprintf( prng_type, sizeof( prng_type ), "Fibonacci" ); - } - else - { - if( kwipe_options.prng == &kwipe_xoroshiro256_prng ) - { - snprintf( prng_type, sizeof( prng_type ), "XORshiro256" ); - } - else - { - snprintf( prng_type, sizeof( prng_type ), "Unknown" ); - } - } - } - } + snprintf( prng_type, sizeof( prng_type ), "Unknown" ); } } pdf_set_font( pdf, "Helvetica-Bold" ); @@ -492,7 +480,7 @@ int create_pdf( kwipe_context_t* ptr ) pdf_set_font( pdf, "Helvetica" ); /****************************************************** - * Final blanking pass if selected, none, zeros or ones + * Final blanking pass if selected: none, zeros, or ones */ if( kwipe_options.noblank ) { @@ -530,7 +518,7 @@ int create_pdf( kwipe_context_t* ptr ) pdf_set_font( pdf, "Helvetica" ); /* ************ - * bytes erased + * Bytes erased */ pdf_add_text( pdf, NULL, "*Bytes Erased:", 12, 60, 230, PDF_GRAY ); pdf_set_font( pdf, "Helvetica-Bold" ); @@ -582,7 +570,7 @@ int create_pdf( kwipe_context_t* ptr ) pdf_set_font( pdf, "Helvetica" ); /************************************************ - * rounds - How many times the method is repeated + * Rounds - How many times the method is repeated */ pdf_add_text( pdf, NULL, "Rounds(completed/requested):", 12, 300, 230, PDF_GRAY ); pdf_set_font( pdf, "Helvetica-Bold" ); @@ -599,7 +587,7 @@ int create_pdf( kwipe_context_t* ptr ) pdf_set_font( pdf, "Helvetica" ); /******************* - * HPA, DCO - LABELS + * HPA, DCO - Labels */ pdf_add_text( pdf, NULL, "HPA/DCO:", 12, 60, 210, PDF_GRAY ); pdf_set_font( pdf, "Helvetica-Bold" ); @@ -617,29 +605,20 @@ int create_pdf( kwipe_context_t* ptr ) snprintf( HPA_size_text, sizeof( HPA_size_text ), "%lli sectors", c->HPA_sectors ); pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_RED ); } - else + else if( c->HPA_status == HPA_DISABLED ) { - if( c->HPA_status == HPA_DISABLED ) - { - snprintf( HPA_size_text, sizeof( HPA_size_text ), "No hidden sectors" ); - pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_DARK_GREEN ); - } - else - { - if( c->HPA_status == HPA_NOT_APPLICABLE ) - { - snprintf( HPA_size_text, sizeof( HPA_size_text ), "Not Applicable" ); - pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_DARK_GREEN ); - } - else - { - if( c->HPA_status == HPA_UNKNOWN ) - { - snprintf( HPA_size_text, sizeof( HPA_size_text ), "Unknown" ); - pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_RED ); - } - } - } + snprintf( HPA_size_text, sizeof( HPA_size_text ), "No hidden sectors" ); + pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_DARK_GREEN ); + } + else if( c->HPA_status == HPA_NOT_APPLICABLE ) + { + snprintf( HPA_size_text, sizeof( HPA_size_text ), "Not Applicable" ); + pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_DARK_GREEN ); + } + else if( c->HPA_status == HPA_UNKNOWN ) + { + snprintf( HPA_size_text, sizeof( HPA_size_text ), "Unknown" ); + pdf_add_text( pdf, NULL, HPA_size_text, text_size_data, 390, 210, PDF_RED ); } pdf_set_font( pdf, "Helvetica" ); @@ -655,45 +634,33 @@ int create_pdf( kwipe_context_t* ptr ) pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_DARK_GREEN ); pdf_set_font( pdf, "Helvetica" ); } - else + else if( c->HPA_status == HPA_ENABLED ) { - if( c->HPA_status == HPA_ENABLED ) - { - snprintf( HPA_status_text, sizeof( HPA_status_text ), "Hidden sectors found!" ); - pdf_set_font( pdf, "Helvetica-Bold" ); - pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_RED ); - pdf_set_font( pdf, "Helvetica" ); - } - else - { - if( c->HPA_status == HPA_DISABLED ) - { - snprintf( HPA_status_text, sizeof( HPA_status_text ), "No hidden sectors" ); - pdf_set_font( pdf, "Helvetica-Bold" ); - pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_DARK_GREEN ); - pdf_set_font( pdf, "Helvetica" ); - } - else - { - if( c->HPA_status == HPA_UNKNOWN ) - { - snprintf( HPA_status_text, sizeof( HPA_status_text ), "Unknown" ); - pdf_set_font( pdf, "Helvetica-Bold" ); - pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_RED ); - pdf_set_font( pdf, "Helvetica" ); - } - else - { - if( c->HPA_status == HPA_NOT_SUPPORTED_BY_DRIVE ) - { - snprintf( HPA_status_text, sizeof( HPA_status_text ), "No hidden sectors **DDNSHDA" ); - pdf_set_font( pdf, "Helvetica-Bold" ); - pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_DARK_GREEN ); - pdf_set_font( pdf, "Helvetica" ); - } - } - } - } + snprintf( HPA_status_text, sizeof( HPA_status_text ), "Hidden sectors found!" ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_RED ); + pdf_set_font( pdf, "Helvetica" ); + } + else if( c->HPA_status == HPA_DISABLED ) + { + snprintf( HPA_status_text, sizeof( HPA_status_text ), "No hidden sectors" ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_DARK_GREEN ); + pdf_set_font( pdf, "Helvetica" ); + } + else if( c->HPA_status == HPA_UNKNOWN ) + { + snprintf( HPA_status_text, sizeof( HPA_status_text ), "Unknown" ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_RED ); + pdf_set_font( pdf, "Helvetica" ); + } + else if( c->HPA_status == HPA_NOT_SUPPORTED_BY_DRIVE ) + { + snprintf( HPA_status_text, sizeof( HPA_status_text ), "No hidden sectors **DDNSHDA" ); + pdf_set_font( pdf, "Helvetica-Bold" ); + pdf_add_text( pdf, NULL, HPA_status_text, text_size_data, 130, 210, PDF_DARK_GREEN ); + pdf_set_font( pdf, "Helvetica" ); } /************ @@ -740,24 +707,21 @@ int create_pdf( kwipe_context_t* ptr ) 170, PDF_RED ); } - else + else if( c->HPA_status == HPA_UNKNOWN ) { - if( c->HPA_status == HPA_UNKNOWN ) - { - pdf_add_ellipse( pdf, NULL, 160, 173, 30, 9, 2, PDF_RED, PDF_BLACK ); - pdf_add_text( pdf, NULL, "Warning", text_size_data, 140, 170, PDF_YELLOW ); - - pdf_add_text( pdf, - NULL, - "HPA/DCO data unavailable, can not determine hidden sector status.", - text_size_data, - 200, - 170, - PDF_RED ); - } + pdf_add_ellipse( pdf, NULL, 160, 173, 30, 9, 2, PDF_RED, PDF_BLACK ); + pdf_add_text( pdf, NULL, "Warning", text_size_data, 140, 170, PDF_YELLOW ); + + pdf_add_text( pdf, + NULL, + "HPA/DCO data unavailable, cannot determine hidden sector status.", + text_size_data, + 200, + 170, + PDF_RED ); } - /* info descripting what bytes erased actually means */ + /* Info describing what bytes erased actually means */ pdf_add_text( pdf, NULL, "* bytes erased: The amount of drive that's been erased at least once", @@ -766,7 +730,7 @@ int create_pdf( kwipe_context_t* ptr ) 137, PDF_BLACK ); - /* meaning of abreviation DDNSHPA */ + /* Meaning of abbreviation DDNSHPA */ if( c->HPA_status == HPA_NOT_SUPPORTED_BY_DRIVE ) { pdf_add_text( @@ -784,7 +748,7 @@ int create_pdf( kwipe_context_t* ptr ) pdf_add_line( pdf, NULL, 360, 65, 550, 66, 1, PDF_GRAY ); pdf_set_font( pdf, "Helvetica-Bold" ); - /* Obtain organisational details from kwipe.conf - See conf.c */ + /* Obtain organizational details from kwipe.conf - See conf.c */ setting = config_lookup( &kwipe_cfg, "Organisation_Details" ); if( config_setting_lookup_string( setting, "Op_Tech_Name", &op_tech_name ) ) { @@ -793,15 +757,15 @@ int create_pdf( kwipe_context_t* ptr ) pdf_set_font( pdf, "Helvetica" ); /*************************************** - * Populate page 2 and 3 with smart data + * Populate page 2 and 3 with SMART data */ kwipe_get_smart_data( c ); /***************************** - * Create the reports filename + * Create the report's filename * * Sanitize the strings that we are going to use to create the report filename - * by converting any non alphanumeric characters to an underscore or hyphon + * by converting any non-alphanumeric characters to an underscore or hyphen */ replace_non_alphanumeric( end_time_text, '-' ); replace_non_alphanumeric( c->device_model, '_' ); @@ -814,8 +778,54 @@ int create_pdf( kwipe_context_t* ptr ) c->device_model, c->device_serial_no ); + /* Save the PDF */ + pdf_save( pdf, c->PDF_filename ); + + /* OpenSSL initialization */ + OpenSSL_add_all_algorithms(); + ERR_load_crypto_strings(); + + /* Generate key and certificate */ + EVP_PKEY* pkey = NULL; + X509* x509 = NULL; + if( generate_key_and_certificate( &pkey, &x509 ) != 1 ) + { + kwipe_log( NWIPE_LOG_ERROR, "Error generating key and certificate" ); + /* Clean up and exit */ + pdf_destroy( pdf ); + return -1; + } + + /* Sign the PDF */ + unsigned char* signature = NULL; + size_t signature_len = 0; + if( sign_pdf( c->PDF_filename, pkey, &signature, &signature_len ) != 1 ) + { + kwipe_log( NWIPE_LOG_ERROR, "Error signing the PDF" ); + /* Clean up and exit */ + EVP_PKEY_free( pkey ); + X509_free( x509 ); + pdf_destroy( pdf ); + return -1; + } + + /* Add signature to the PDF */ + add_signature_to_pdf( pdf, c, signature, signature_len ); + + /* Save the updated PDF */ pdf_save( pdf, c->PDF_filename ); + + /* Free resources */ + free( signature ); + EVP_PKEY_free( pkey ); + X509_free( x509 ); pdf_destroy( pdf ); + + /* OpenSSL cleanup */ + EVP_cleanup(); + CRYPTO_cleanup_all_ex_data(); + ERR_free_strings(); + return 0; } @@ -832,7 +842,7 @@ int kwipe_get_smart_data( kwipe_context_t* c ) char final_cmd_smartctl[sizeof( smartctl_command3 ) + 256]; char result[512]; char smartctl_labels_to_anonymize[][18] = { - "serial number:", "lu wwn device id:", "logical unit id:", "" /* Don't remove this empty string !, important */ + "serial number:", "lu wwn device id:", "logical unit id:", "" /* Don't remove this empty string! Important */ }; int idx, idx2, idx3; @@ -842,15 +852,14 @@ int kwipe_get_smart_data( kwipe_context_t* c ) final_cmd_smartctl[0] = 0; - /* Determine whether we can access smartctl, required if the PATH environment is not setup ! (Debian sid 'su' as - * opposed to 'su -' */ + /* Determine whether we can access smartctl */ if( system( "which smartctl > /dev/null 2>&1" ) ) { if( system( "which /sbin/smartctl > /dev/null 2>&1" ) ) { if( system( "which /usr/bin/smartctl > /dev/null 2>&1" ) ) { - kwipe_log( NWIPE_LOG_WARNING, "Command not found. Install smartmontools !" ); + kwipe_log( NWIPE_LOG_WARNING, "Command not found. Install smartmontools!" ); } else { @@ -879,31 +888,26 @@ int kwipe_get_smart_data( kwipe_context_t* c ) } else { - x = 50; // left side of page - y = 630; // top row of page + x = 50; // Left side of page + y = 630; // Top row of page page_number = 2; - /* Create Page 2 of the report. This shows the drives smart data - */ + /* Create Page 2 of the report. This shows the drive's SMART data */ page = pdf_append_page( pdf ); - /* Create the header and footer for page 2, the start of the smart data */ - snprintf( page_title, sizeof( page_title ), "Page %i - Smart Data", page_number ); + /* Create the header and footer for page 2, the start of the SMART data */ + snprintf( page_title, sizeof( page_title ), "Page %i - SMART Data", page_number ); create_header_and_footer( c, page_title ); /* Read the output a line at a time - output it. */ while( fgets( result, sizeof( result ) - 1, fp ) != NULL ) { - /* Convert the label, i.e everything before the ':' to lower case, it's required to - * convert to lower case as smartctl seems to use inconsistent case when labeling - * for serial number, i.e mostly it produces labels "Serial Number:" but occasionally - * it produces a label "Serial number:" */ - + /* Convert the label (everything before ':') to lowercase */ idx = 0; while( result[idx] != 0 && result[idx] != ':' ) { - /* If upper case alpha character, change to lower case */ + /* If uppercase alpha character, change to lowercase */ if( result[idx] >= 'A' && result[idx] <= 'Z' ) { result[idx] += 32; @@ -913,7 +917,7 @@ int kwipe_get_smart_data( kwipe_context_t* c ) if( kwipe_options.quiet == 1 ) { - for( idx2 = 0; idx2 < 3; idx2++ ) + for( idx2 = 0; smartctl_labels_to_anonymize[idx2][0] != '\0'; idx2++ ) { if( strstr( result, &smartctl_labels_to_anonymize[idx2][0] ) ) { @@ -945,11 +949,12 @@ int kwipe_get_smart_data( kwipe_context_t* c ) page_number++; y = 630; - /* create the header and footer for the next page */ - snprintf( page_title, sizeof( page_title ), "Page %i - Smart Data", page_number ); + /* Create the header and footer for the next page */ + snprintf( page_title, sizeof( page_title ), "Page %i - SMART Data", page_number ); create_header_and_footer( c, page_title ); } } + pclose( fp ); set_return_value = 0; } } @@ -964,7 +969,7 @@ void create_header_and_footer( kwipe_context_t* c, char* page_title ) { /************************************************************************** * Create header and footer on most recently added page, with the exception - * of the green tick/red icon which is set from the 'status' section below. + * of the status icon which is set from the 'status' section below. */ pdf_add_text_wrap( pdf, NULL, pdf_footer, 12, 0, 30, PDF_BLACK, page_width, PDF_ALIGN_CENTER, &height ); pdf_add_line( pdf, NULL, 50, 50, 550, 50, 3, PDF_BLACK ); @@ -983,8 +988,8 @@ void create_header_and_footer( kwipe_context_t* c, char* page_title ) pdf_add_barcode( pdf, NULL, PDF_BARCODE_128A, 100, 790, 400, 25, barcode, PDF_BLACK ); /********************************************************** - * Display the appropriate status icon, top right on page on - * most recently added page. + * Display the appropriate status icon at the top right on + * the most recently added page. */ switch( status_icon ) { @@ -1002,7 +1007,7 @@ void create_header_and_footer( kwipe_context_t* c, char* page_title ) case STATUS_ICON_RED_CROSS: - // Display the red cross in the header + /* Display the red cross in the header */ pdf_add_image_data( pdf, NULL, 450, 665, 100, 100, bin2c_redcross_jpg, 60331 ); break; @@ -1011,3 +1016,169 @@ void create_header_and_footer( kwipe_context_t* c, char* page_title ) break; } } + +/* Function to generate a key pair and a self-signed certificate */ +int generate_key_and_certificate( EVP_PKEY** pkey, X509** x509 ) +{ + int ret = 0; + EVP_PKEY_CTX* pkey_ctx = NULL; + X509_NAME* name = NULL; + + /* Generate key */ + pkey_ctx = EVP_PKEY_CTX_new_id( EVP_PKEY_RSA, NULL ); + if( !pkey_ctx ) + { + ret = -1; + goto cleanup; + } + + if( EVP_PKEY_keygen_init( pkey_ctx ) <= 0 ) + { + ret = -1; + goto cleanup; + } + + if( EVP_PKEY_CTX_set_rsa_keygen_bits( pkey_ctx, 2048 ) <= 0 ) + { + ret = -1; + goto cleanup; + } + + if( EVP_PKEY_keygen( pkey_ctx, pkey ) <= 0 ) + { + ret = -1; + goto cleanup; + } + + /* Generate certificate */ + *x509 = X509_new(); + ASN1_INTEGER_set( X509_get_serialNumber( *x509 ), 1 ); + X509_gmtime_adj( X509_get_notBefore( *x509 ), 0 ); + X509_gmtime_adj( X509_get_notAfter( *x509 ), 31536000L ); /* Validity: 1 year */ + X509_set_pubkey( *x509, *pkey ); + + /* Set name */ + name = X509_get_subject_name( *x509 ); + X509_NAME_add_entry_by_txt( name, "C", MBSTRING_ASC, (unsigned char*) "DE", -1, -1, 0 ); + X509_NAME_add_entry_by_txt( name, "O", MBSTRING_ASC, (unsigned char*) "Nwipe", -1, -1, 0 ); + X509_NAME_add_entry_by_txt( name, "CN", MBSTRING_ASC, (unsigned char*) "Nwipe Certificate", -1, -1, 0 ); + + /* Self-signed */ + X509_set_issuer_name( *x509, name ); + + /* Sign certificate */ + if( !X509_sign( *x509, *pkey, EVP_sha256() ) ) + { + ret = -1; + goto cleanup; + } + + ret = 1; /* Success */ + +cleanup: + if( pkey_ctx ) + EVP_PKEY_CTX_free( pkey_ctx ); + if( ret != 1 ) + { + if( *pkey ) + EVP_PKEY_free( *pkey ); + if( *x509 ) + X509_free( *x509 ); + } + return ret; +} + +/* Function to sign the PDF */ +int sign_pdf( const char* pdf_filename, EVP_PKEY* pkey, unsigned char** signature, size_t* signature_len ) +{ + FILE* pdf_file = fopen( pdf_filename, "rb" ); + if( !pdf_file ) + { + perror( "Cannot open PDF file" ); + return -1; + } + + /* Read PDF file and compute hash */ + EVP_MD_CTX* md_ctx = EVP_MD_CTX_new(); + if( !md_ctx ) + { + perror( "Failed to create EVP_MD_CTX" ); + fclose( pdf_file ); + return -1; + } + + if( EVP_DigestSignInit( md_ctx, NULL, EVP_sha256(), NULL, pkey ) <= 0 ) + { + perror( "EVP_DigestSignInit failed" ); + EVP_MD_CTX_free( md_ctx ); + fclose( pdf_file ); + return -1; + } + + unsigned char buffer[4096]; + size_t bytes_read; + while( ( bytes_read = fread( buffer, 1, sizeof( buffer ), pdf_file ) ) > 0 ) + { + if( EVP_DigestSignUpdate( md_ctx, buffer, bytes_read ) <= 0 ) + { + perror( "EVP_DigestSignUpdate failed" ); + EVP_MD_CTX_free( md_ctx ); + fclose( pdf_file ); + return -1; + } + } + fclose( pdf_file ); + + /* Finalize signature */ + if( EVP_DigestSignFinal( md_ctx, NULL, signature_len ) <= 0 ) + { + perror( "EVP_DigestSignFinal (get length) failed" ); + EVP_MD_CTX_free( md_ctx ); + return -1; + } + + *signature = malloc( *signature_len ); + if( !*signature ) + { + perror( "Memory allocation failed for signature" ); + EVP_MD_CTX_free( md_ctx ); + return -1; + } + + if( EVP_DigestSignFinal( md_ctx, *signature, signature_len ) <= 0 ) + { + perror( "EVP_DigestSignFinal failed" ); + EVP_MD_CTX_free( md_ctx ); + free( *signature ); + return -1; + } + + EVP_MD_CTX_free( md_ctx ); + return 1; /* Success */ +} + +/* Function to add the signature to the PDF */ +void add_signature_to_pdf( struct pdf_doc* pdf, kwipe_context_t* c, unsigned char* signature, size_t signature_len ) +{ + char* signature_hex = malloc( signature_len * 2 + 1 ); + for( size_t i = 0; i < signature_len; i++ ) + { + sprintf( &signature_hex[i * 2], "%02x", signature[i] ); + } + signature_hex[signature_len * 2] = '\0'; + + /* Add a new page to display the signature */ + struct pdf_object* signature_page = pdf_append_page( pdf ); + + /* Create header and footer for the signature page */ + char page_title[50]; + snprintf( page_title, sizeof( page_title ), "Digital Signature" ); + create_header_and_footer( c, page_title ); + + /* Add signature as text */ + pdf_set_font( pdf, "Courier" ); + pdf_add_text( pdf, NULL, "Digital Signature (Hex):", 12, 50, 600, PDF_BLACK ); + pdf_add_text_wrap( pdf, NULL, signature_hex, 10, 50, 580, PDF_BLACK, 500, PDF_ALIGN_LEFT, &height ); + + free( signature_hex ); +} diff --git a/src/create_pdf.h b/src/create_pdf.h index 6d42fb4f..4f6d653d 100644 --- a/src/create_pdf.h +++ b/src/create_pdf.h @@ -1,5 +1,5 @@ -/*. - * create_pdf.h: The header file for the pdf creation routines +/* + * create_pdf.h: The header file for the PDF creation routines * * Copyright https://github.com/PartialVolume/shredos.x86_64 * @@ -21,32 +21,71 @@ #ifndef CREATE_PDF_H_ #define CREATE_PDF_H_ +#include "kwipe.h" /* Include kwipe context */ +#include "PDFGen/pdfgen.h" /* Include PDFGen structures */ + +/* OpenSSL headers */ +#include +#include + #define MAX_PDF_FOOTER_TEXT_LENGTH 100 #define STATUS_ICON_GREEN_TICK 1 #define STATUS_ICON_YELLOW_EXCLAMATION 2 #define STATUS_ICON_RED_CROSS 3 -/* Additional colors that supplement the standard colors in pdfgen.h - */ -/*! Utility macro to provide gray */ +/* Additional colors that supplement the standard colors in pdfgen.h */ #define PDF_DARK_GREEN PDF_RGB( 0, 0x64, 0 ) - -/*! Utility macro to provide gray */ #define PDF_GRAY PDF_RGB( 0x5A, 0x5A, 0x5A ) - -/*! Utility macro to provide gray */ #define PDF_YELLOW PDF_RGB( 0xFF, 0xFF, 0x5A ) /** * Create the disk erase report in PDF format - * @param pointer to a drive context - * @return returns 0 on success < 1 on error + * @param ptr Pointer to a drive context + * @return Returns 0 on success, < 1 on error */ int create_pdf( kwipe_context_t* ptr ); -int kwipe_get_smart_data( kwipe_context_t* ); +/** + * Get SMART data and add it to the PDF + * @param c Pointer to kwipe context + * @return Returns 0 on success, non-zero on error + */ +int kwipe_get_smart_data( kwipe_context_t* c ); + +/** + * Create header and footer for the PDF pages + * @param c Pointer to kwipe context + * @param page_title Title of the page + */ +void create_header_and_footer( kwipe_context_t* c, char* page_title ); + +/* New functions for OpenSSL integration */ +/** + * Generate a key pair and a self-signed certificate + * @param pkey Pointer to store the generated EVP_PKEY + * @param x509 Pointer to store the generated X509 certificate + * @return Returns 1 on success, -1 on error + */ +int generate_key_and_certificate( EVP_PKEY** pkey, X509** x509 ); -void create_header_and_footer( kwipe_context_t*, char* ); +/** + * Sign the PDF with the generated private key + * @param pdf_filename Path to the PDF file + * @param pkey Private key used for signing + * @param signature Pointer to store the signature + * @param signature_len Pointer to store the length of the signature + * @return Returns 1 on success, -1 on error + */ +int sign_pdf( const char* pdf_filename, EVP_PKEY* pkey, unsigned char** signature, size_t* signature_len ); + +/** + * Add the signature to the PDF + * @param pdf Pointer to the PDF document + * @param c Pointer to kwipe context + * @param signature The signature data + * @param signature_len Length of the signature data + */ +void add_signature_to_pdf( struct pdf_doc* pdf, kwipe_context_t* c, unsigned char* signature, size_t signature_len ); #endif /* CREATE_PDF_H_ */