RDK Documentation (Open Sourced RDK Components)
rdm_rsa_signature_verify.c
1 /*
2  * If not stated otherwise in this file or this component's Licenses.txt file the
3  * following copyright and licenses apply:
4  *
5  * Copyright 2018 RDK Management
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18 */
19 
20 
21 
22 #include "rdm_rsa_signature_verify.h"
23 
24 #if defined(DEBUG_ENABLED)
25 static time_t timebuffer;
26 #endif
27 
28 /**
29  * @addtogroup RDM_API
30  * @{
31  */
32 
33 /**
34  * @brief This function outputs all the run's data to stdout and also to a binary file.
35  *
36  * @param[in] buffer Data buffer
37  * @param[in] buffer_size Length of buffer
38  * @param[in] name Binary file name
39  *
40  */
41 void dump_buffer(void *buffer, int buffer_size, char *name)
42 {
43 #if defined(DEBUG_ENABLED)
44  int i;
45 
46  /** this is for outputting all the run's data in binary files */
47  struct tm *tm = localtime(&timebuffer);
48  char s[128];
49  static int filecount=0;
50 
51  memset(s,0,sizeof(s));
52  strftime(s, sizeof(s), "%T-", tm);
53  /* should be sndebug_print */
54  sdebug_print(s+strlen(s),"%d-",filecount);
55 
56  strncat(s,name,sizeof(s)-strlen(name)-1);
57  strncat(s,".bin",sizeof(s)-strlen(".bin")-1);
58 
59  filecount++;
60 
61  for(i = 0;i < buffer_size;++i) {
62  debug_print("buffer[%d]=(%c) [%2.2x]\n",i, ((char *)buffer)[i],((unsigned char *)buffer)[i]);
63  }
64 
65  FILE *binout = fopen(s,"wb");
66  if ( binout == NULL ) return;
67  fwrite(buffer,buffer_size,1,binout);
68  fclose(binout);
69 #endif
70 }
71 
72  /**
73  * @brief This function is used to convert asciihex data into binary format.
74  *
75  * @param[in] asciihex - Pointer to ascii hex string (not necessarily 0-term)
76  * @param[in] asciihex_length - Length of ascii input string
77  * @param[out] bin - Pointer to output buffer
78  * @param[out] bin_length - Pointer length of output buffer
79  *
80  * @return Returns the status of the operation.
81  * @retval -1 Bad input args: null pointers or insufficient length, length returned if too small.
82  * @retval 0 All inputs OK, conversion performed.
83  *
84  * @note ASCII '0' = 0x30,'A' = 0x41. Case conversion/enforcement is based on same assumption.
85  */
86 static
87 int asciihex_to_bin( const char *asciihex, size_t asciihex_length, unsigned char *bin, size_t *bin_length )
88 {
89  if ( asciihex == NULL || bin == NULL || bin_length == NULL || (asciihex_length & 1) ) {
90  return -1;
91  }
92  if ( *bin_length < asciihex_length/2 ) {
93  *bin_length = asciihex_length/2;
94  return -1;
95  }
96 
97  while ( asciihex_length > 0 ) {
98  unsigned char uc = (*asciihex++);
99  if ( uc > '9' ) { uc &= ~0x20; uc -= ('A'-10); } else { uc -= '0'; }
100  *bin = uc << 4;
101  uc = (*asciihex++);
102  if ( uc > '9' ) { uc &= ~0x20; uc -= ('A'-10); } else { uc -= '0'; }
103  *bin++ |= uc;
104  asciihex_length -= 2;
105  }
106 
107  return 0;
108 }
109 
110 /**
111  * @brief This function is used to convert binary data into asciihex format.
112  *
113  * @param[in] bin Pointer to binary input
114  * @param[in] bin_length Length of binary input (bytes)
115  * @param[out] asciihex Pointer to ascii hex destination
116  * @param[out] asciihex_length Pointer to length of output buffer (must be at least 2x bin_length!)
117  *
118  * @note THE SIGNATURE VALIDATION PACKAGES REQUIRES THE FILE IS HASHED AND THEN CONVERTED
119  * TO ASCII HEX USING "xxd -ps -c 2048 binary_hash_file" FOR SIGNING. THE SIGNED MESSAGE IS LOWER-CASE
120  * HEX ASCII. SO WHEN THE HASH OVER THE DATA TO BE VERIFIED IS CONVERTED BACK TO BINARY FOR VERIFICATION,
121  * THE CONVERSION MUST BE TO LOWER-CASE HEX ASCII.
122  *
123  * @return Returns the status of the operation.
124  * @retval -1 Bad input args, length returned if too small.
125  * @retval 0 All inputs OK, conversion returned.
126  */
127 static
128 int bin_to_asciihex( const unsigned char *bin, size_t bin_length, char *asciihex, size_t *asciihex_length )
129 {
130  if ( bin == NULL || asciihex == NULL || asciihex_length == NULL ) {
131  return -1;
132  }
133  if ( *asciihex_length < bin_length * 2 ) {
134  *asciihex_length = bin_length * 2;
135  return -1;
136  }
137  size_t i;
138  for( i=0; i < bin_length; i++, bin++ ) {
139  unsigned char c = (*bin >> 4) + '0';
140  if ( c > '9' ) {
141  c = c-('9'+1)+'a';
142  }
143  *asciihex++ = c;
144  c = (*bin & 0x0f) + '0';
145  if ( c > '9' ) {
146  c = c-('9'+1)+'a';
147  }
148  *asciihex++ = c;
149  }
150  return 0;
151 }
152 
153 static int prepare_sig_file(char *sig_file) {
154  char buffer[512] = {0};
155  int read = 0, skip = 0, len = 0;
156  char *mv_command = NULL;
157 
158  FILE *file_in = fopen(sig_file, "r");
159  FILE *file_out = fopen(RDM_TMP_SIGFILE, "w+");
160 
161  if (NULL == file_in || NULL == file_out)
162  return 1;
163 
164  while((read = fread(buffer, sizeof(char), sizeof(buffer), file_in)) > 0)
165  {
166  if(0 == skip && read > 6) {
167  //skip first 6 bytes
168  fwrite(&buffer[6], sizeof(char), read-6, file_out);
169  skip = 1;
170  } else {
171  fwrite(buffer, sizeof(char), read, file_out);
172  }
173  }
174 
175  fclose(file_out);
176  fclose(file_in);
177 
178  len = strlen("/bin/mv") + strlen(RDM_TMP_SIGFILE) + strlen(sig_file) + 3;
179  mv_command = (char*) calloc(len, sizeof(char));
180  sprintf(mv_command, "/bin/mv %s %s", RDM_TMP_SIGFILE, sig_file);
181 
182  system(mv_command);
183  free(mv_command);
184 
185  return 0;
186 }
187 
188 static int prepare_app_manifest(char *etc_manifest_file, char *cache_manifest_file, char* padding_file, char *prefix) {
189  char *line = NULL;
190  size_t len = 0;
191  char *new_line = NULL;
192 
193  FILE *file_in = fopen(etc_manifest_file, "r");
194  FILE *file_out = fopen(cache_manifest_file, "w+");
195 
196  if(file_in == NULL || file_out == NULL) {
197  return 1;
198  }
199 
200  while(getline(&line, &len, file_in) != -1) {
201  if (NULL == new_line)
202  new_line = (char *) malloc(sizeof(char) * (strlen(line) + strlen(prefix) + 1));
203  else
204  new_line = (char *) realloc(new_line, sizeof(char) * (strlen(line) + strlen(prefix) + 1));
205  sprintf(new_line, "%s%s", prefix, line);
206  fwrite(new_line, sizeof(char), strlen(new_line), file_out);
207  }
208 
209  //add path to padding file
210  fprintf(file_out, "%s\n", padding_file);
211 
212  if (new_line)
213  free(new_line);
214  if (line)
215  free(line);
216 
217  fclose(file_in);
218  fclose(file_out);
219 
220  return 0;
221 }
222 
223 static int prepare_kms_pubkey() {
224  int ret;
225  ret = system("/usr/bin/configparamgen jx /etc/rdm/vjyrepbsb.ijv /tmp/vstuvwx.file");
226  return WEXITSTATUS(ret);
227 }
228 
229 /**
230  *
231  * @brief This function prepares the rdm files for signature verification
232  * Does the following -
233  * 1. Remove header added by KMS
234  * 2. Prepare cpe manifest file with correct path to extracted files
235  * 3. Decrypt kms public key
236  */
237 static int prepare_rdm_files_for_sign_verification(char *cache_dir, char *app_name)
238 {
239  char *app_cache_dir = NULL;
240  char *app_home_dir = NULL;
241  char *path_to_sig_file = NULL;
242  char *cache_app_manifest = NULL;
243  char *etc_app_manifest = NULL;
244  char *path_to_padding_file = NULL;
245  int len, ret;
246 
247  len = strlen(cache_dir) + strlen(RDM_DOWNLOADS_DIR) + strlen(app_name) + 2;
248  app_cache_dir = (char*) calloc(len, sizeof(char));
249  sprintf(app_cache_dir, "%s%s%s/", cache_dir, RDM_DOWNLOADS_DIR, app_name);
250 
251  len = strlen(cache_dir) + strlen(app_name) + 3;
252  app_home_dir = (char*) calloc(len, sizeof(char));
253  sprintf(app_home_dir, "%s/%s/", cache_dir, app_name);
254 
255  len = strlen(app_cache_dir) + strlen(app_name) + strlen(RDM_SIGFILE_SUFFIX) + 1;
256  path_to_sig_file = (char*) calloc(len, sizeof(char));
257  sprintf(path_to_sig_file, "%s%s%s", app_cache_dir, app_name, RDM_SIGFILE_SUFFIX);
258 
259  ret = prepare_sig_file(path_to_sig_file);
260 
261  free(path_to_sig_file);
262 
263  if (ret) {
264  free(app_cache_dir);
265  free(app_home_dir);
266  return ret;
267  }
268 
269  len = strlen(RDM_MANIFEST_DIR) + strlen(app_name) + strlen(RDM_MANIFEST_SUFFIX) + 1;
270  etc_app_manifest = (char*) calloc(len, sizeof(char));
271  sprintf(etc_app_manifest, "%s%s%s", RDM_MANIFEST_DIR, app_name, RDM_MANIFEST_SUFFIX);
272 
273  len = strlen(app_home_dir) + strlen(app_name) + strlen(RDM_MANIFEST_SUFFIX) + 1;
274  cache_app_manifest = (char*) calloc(len, sizeof(char));
275  sprintf(cache_app_manifest, "%s%s%s", app_home_dir, app_name, RDM_MANIFEST_SUFFIX);
276 
277  len = strlen(app_cache_dir) + strlen(RDM_KMS_PADDING_FILE) + 1;
278  path_to_padding_file = (char*) calloc(len, sizeof(char));
279  sprintf(path_to_padding_file, "%s%s", app_cache_dir, RDM_KMS_PADDING_FILE);
280 
281  ret = prepare_app_manifest(etc_app_manifest, cache_app_manifest, path_to_padding_file, app_home_dir);
282 
283  free(path_to_padding_file);
284  free(app_cache_dir);
285  free(app_home_dir);
286  free(cache_app_manifest);
287  free(etc_app_manifest);
288 
289  if (ret) {
290  return ret;
291  }
292 
293  ret = prepare_kms_pubkey();
294 
295  return ret;
296 }
297 
298 /**
299  *
300  * @brief This function prepares the rdm files for signature verification and invokes
301  * the kms openssl verification api
302  */
303 int rdm_signature_verify(char *cache_dir, char *app_name, int prepare_files)
304 {
305  int status = 1, len = 0;
306  int outputMsgLen=REPLY_MSG_LEN;
307  char outputMsg[REPLY_MSG_LEN] = "no response received";
308  char *dataFile=NULL, *sigFile=NULL;
309 
310  if (NULL == cache_dir || NULL == app_name)
311  return status;
312 
313  if (1 == prepare_files) {
314  if (0 != prepare_rdm_files_for_sign_verification(cache_dir, app_name)) {
315  printf("prepare_rdm_files_for_sign_verification failed\n");
316  return status;
317  }
318  } else {
319  if (0 != prepare_kms_pubkey()) {
320  printf("prepare_kms_pubkey failed\n");
321  return status;
322  }
323  }
324 
325  /* Initialize the openSSL crypto library and configurations */
326  init_ssl_lib();
327 
328  len = strlen(cache_dir) + 2 * strlen(app_name) + strlen(RDM_MANIFEST_SUFFIX) + 3;
329  dataFile = (char*) calloc(len, sizeof(char));
330  sprintf(dataFile, "%s/%s/%s%s", cache_dir, app_name, app_name, RDM_MANIFEST_SUFFIX);
331 
332  len = strlen(cache_dir) + strlen(RDM_DOWNLOADS_DIR) + 2 * strlen(app_name) + strlen(RDM_SIGFILE_SUFFIX) + 2;
333  sigFile = (char*) calloc(len, sizeof(char));
334  sprintf(sigFile, "%s%s%s/%s%s", cache_dir, RDM_DOWNLOADS_DIR, app_name, app_name, RDM_SIGFILE_SUFFIX);
335 
336  status = rdm_openssl_rsa_file_signature_verify( dataFile, -1, sigFile, RDM_KMS_PUB_KEY, outputMsg, &outputMsgLen );
337  if ( status == retcode_success ) {
338  printf("RSA Signature Validation Success\n");
339  status = 0;
340  } else {
341  printf("RSA Signature Verification Failed\n");
342  }
343 
344  free(dataFile);
345  free(sigFile);
346 
347  unlink(RDM_KMS_PUB_KEY);
348  return status;
349 }
350 
351 /**
352  *
353  * @brief This function initializes the openSSL crypto library and configurations
354  *
355  */
356 void init_ssl_lib(void)
357 {
358  static int ssl_init=0;
359 
360  if ( ssl_init ) {return;}
361  /* Load the human readable error strings for libcrypto */
362  ERR_load_crypto_strings();
363 
364  /* Load all digest and cipher algorithms */
365  OpenSSL_add_all_algorithms();
366 
367  /* Load config file, and other important initialisation */
368  OPENSSL_config(NULL);
369  ssl_init++;
370 #if defined(DEBUG_ENABLED)
371  timebuffer = time(NULL);
372 #endif
373 }
374 
375 /**
376  *
377  * @brief This function decodes the signature file.
378  *
379  * @param[in] sig_file Pointer to signature file
380  * @param[in] sig_buffer Output signature buffer
381  * @param[in] sig_size Pointer to signature file size
382  *
383  * @ret returns -1 Bad parameters, including bad length. *buffer_len contains required len.
384  * @ret returns 2 Failed reading sig_file, no sig check done, reply_msg has response
385  */
386 static
387 int read_signature_file( const char *sig_file, unsigned char **sig_buffer, int *sig_size )
388 {
389  FILE *sig_fh;
390 
391  /* file buffer */
392  char buf[RSA2048_ASCII_SIGNATURE_LEN];
393 
394  /* Keep internal buffer, return to caller */
395  static unsigned char sig[RSA2048_SIGNATURE_LEN];
396 
397  if ( sig_file == NULL || sig_buffer == NULL || sig_size == NULL ) {
398  debug_print("read_signature_file parm error\n");
399  return retcode_param_error;
400  }
401 
402  /**
403  * read and convert file here
404  */
405 
406  sig_fh = fopen( sig_file, "r" ); /* its ascii. not binary. this keeps us honest*/
407  if ( sig_fh == NULL ) {
408  debug_print("read_signature_file file open error\n");
409  return retcode_sigfile_err;
410  }
411 
412  size_t nread = fread( buf, 1, RSA2048_ASCII_SIGNATURE_LEN, sig_fh );
413  if ( nread != (RSA2048_ASCII_SIGNATURE_LEN) || ferror( sig_fh ) ) {
414  fclose( sig_fh );
415  debug_print("read_signature_file file read error\n");
416  return retcode_sigfile_err;
417  }
418  fclose( sig_fh );
419 
420 #if defined(DEBUG_ENABLED)
421  char buf2[RSA2048_ASCII_SIGNATURE_LEN + 1];
422  memcpy(buf2, buf ,RSA2048_ASCII_SIGNATURE_LEN);
423  buf2[RSA2048_ASCII_SIGNATURE_LEN] = 0;
424  debug_print("Sig file contents:\n%s\n",buf2);
425 #endif
426  size_t sig_len = sizeof( sig );
427  if ( asciihex_to_bin( buf, RSA2048_ASCII_SIGNATURE_LEN, sig, &sig_len ) != 0 ) {
428  return -1;
429  }
430  *sig_buffer = sig;
431  *sig_size = RSA2048_SIGNATURE_LEN;
432  return 0;
433 }
434 /** @} */ //END OF GROUP RDM_API
435 
436 /**
437  * @addtogroup RDM_TYPES
438  * @{
439  */
440 
441 static
442 int manifest_file_size(const char *data_file, int *buffer_size)
443 {
444  FILE *data_fh=NULL;
445  int retval=0;
446  data_fh = fopen( data_file, "r" );
447  if ( data_fh == NULL )
448  {
449  debug_print("manifest_file_size(): datafile open error\n");
450  retval = retcode_datafile_err;
451  goto error;
452  }
453  fseek(data_fh, 0, SEEK_END);
454  // calculating the size of the cpemanifest file
455  *buffer_size = ftell(data_fh) + 1;
456 
457  if ( fseek( data_fh, 0, SEEK_END ) != 0 ) {
458  retval = retcode_datafile_err;
459  goto error;
460  }
461 
462  if ( ferror( data_fh ) ) {
463  retval = retcode_datafile_err;
464  goto error;
465  }
466 
467 error:
468  if ( data_fh != NULL ) fclose( data_fh );
469  return retval;
470 }
471 
472 /** @} */ //END OF GROUP RDM_TYPES
473 
474 
475 /**
476  * @addtogroup RDM_API
477  * @{
478  */
479 
480 /**
481  * @brief This function is used to read and digest the data file.
482  *
483  * @param[in] data_file The file to calculate a hash over
484  * @param[in] hash_buffer Pointer to memory to receive hash
485  * @param[in] buffer_len Pointer to int length of callers buffer
486  *
487  * @ret returns 0 Hash is complete and in caller's buffer.
488  * @ret returns 1 Data file error.
489  * @ret returns -1 Bad parameters, including bad length.
490  * @ret returns 3 Openssl returned some sort of error.
491  */
492 static
493 int rdm_openssl_file_hash_sha256( const char *data_file, size_t file_len, unsigned char *hash_buffer, int *buffer_len )
494 {
495  int BUFSIZE;
496  if ( manifest_file_size(data_file, &BUFSIZE) != 0 )
497  return retcode_datafile_err;
498  EVP_MD_CTX *mdctx=NULL;
499  FILE *data_fh=NULL;
500  unsigned char* buffer= (unsigned char*)calloc(sizeof(unsigned char), BUFSIZE );
501  int retval;
502 
503  debug_print("rdm_openssl_file_hash_sha256() Entry\n");
504 
505  if ( data_file == NULL || hash_buffer == NULL || buffer_len == NULL ) {
506  debug_print("rdm_openssl_file_hash_sha256(): Invalid param error\n");
507  retval=retcode_param_error;
508  goto error;
509  }
510  if ( *buffer_len < SHA256_DIGEST_LENGTH ) {
511  *buffer_len = SHA256_DIGEST_LENGTH;
512  debug_print("rdm_openssl_file_hash_sha256(): Wrong param error\n");
513  retval=retcode_param_error;
514  goto error;
515  }
516  /**
517  * read and digest the data file
518  */
519  data_fh = fopen( data_file, "r" );
520  if ( data_fh == NULL ) {
521  debug_print("rdm_openssl_file_hash_sha256(): datafile open error\n");
522  retval=retcode_datafile_err;
523  goto error;
524  }
525 
526  /* init ret code to ssl error */
527  retval = retcode_ssl_err;
528 
529  if((mdctx = EVP_MD_CTX_create()) == NULL) {
530  debug_print("rdm_openssl_file_hash_sha256(): Digest Context Initialize Failed\n");
531  goto error;
532  }
533 
534  if(1 != EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) {
535  debug_print("rdm_openssl_file_hash_sha256(): Digest Context Type Setup Failed\n");
536  goto error;
537  }
538 
539  retval = retcode_datafile_err;
540  if ( file_len == (size_t)-1 ) {
541  if ( fseek( data_fh, 0, SEEK_END ) != 0 ) {
542  goto error;
543  }
544  file_len = (size_t)ftell( data_fh );
545  if ( fseek( data_fh, 0, SEEK_SET ) != 0 ) {
546  goto error;
547  }
548  }
549  size_t bytesread=0;
550 
551  do {
552  size_t bytes_to_read = ( file_len < sizeof(buffer) ? file_len : sizeof(buffer) );
553  bytesread = fread(buffer, 1, bytes_to_read, data_fh );
554  if ( bytesread > 0 ) {
555  if(1 != EVP_DigestUpdate(mdctx, buffer, bytesread)) {
556  goto error;
557  }
558  }
559  file_len -= bytes_to_read;
560  } while ( file_len > 0 );
561 
562  if ( ferror( data_fh ) ) {
563  retval = retcode_datafile_err;
564  goto error;
565  }
566 
567  int hashval_len;
568  if( 1 != EVP_DigestFinal_ex(mdctx, hash_buffer, &hashval_len) ) {
569  goto error;
570  }
571  if ( hashval_len != SHA256_DIGEST_LENGTH ) {
572  goto error;
573  }
574  retval = 0;
575 
576 error:
577 
578  if ( data_fh != NULL ) fclose( data_fh );
579  if ( mdctx != NULL ) EVP_MD_CTX_destroy( mdctx );
580  if ( buffer != NULL ) free( buffer );
581  return retval;
582 }
583 
584 /**
585  * @brief This function is used to initiating signature validation of individual package components.
586  *
587  * @param[in] data_file Manifest file having path for all package components
588  * @param[out] hash_buffer Pointer to memory to receive hash
589  * @param[out] buffer_len Pointer to int length of callers buffer
590  *
591  * @return Reurns the status of operation.
592  *
593  * @retval 0 Hash is complete and in caller's buffer.
594  * @retval 1 Data file error.
595  * @retval -1 Bad parameters, including bad length.
596  * @retval 3 Openssl returned some sort of error.
597  */
598 static
599 int rdm_openssl_file_hash_sha256_pkg_components( const char *data_file, size_t file_len, unsigned char *hash_buffer, int *buffer_len )
600 {
601  int BUFSIZE;
602  if ( manifest_file_size(data_file, &BUFSIZE) != 0 )
603  return retcode_datafile_err;
604  EVP_MD_CTX *mdctx=NULL;
605  FILE *manifest_fh=NULL;
606  FILE *data_fh=NULL;
607  unsigned char* buffer= (unsigned char*)calloc(sizeof(unsigned char), BUFSIZE );
608  char *manifest=NULL;
609  char *path_buff=NULL;
610  int retval;
611  size_t bytesread=0;
612 
613  debug_print("rdm_openssl_file_hash_sha256_pkg_components() Entry\n");
614 
615  if ( data_file == NULL || hash_buffer == NULL || buffer_len == NULL ) {
616  debug_print("rdm_openssl_file_hash_sha256_pkg_components(): Invalid param error\n");
617  retval=retcode_param_error;
618  goto error;
619  }
620  if ( *buffer_len < SHA256_DIGEST_LENGTH ) {
621  *buffer_len = SHA256_DIGEST_LENGTH;
622  debug_print("rdm_openssl_file_hash_sha256_pkg_components(): Wrong param error\n");
623  retval=retcode_param_error;
624  goto error;
625  }
626  /**
627  * Read and digest the manifest file
628  */
629  manifest_fh = fopen( data_file, "r" );
630  if ( manifest_fh == NULL ) {
631  debug_print("rdm_openssl_file_hash_sha256_pkg_components(): manifest file open error\n");
632  retval=retcode_datafile_err;
633  goto error;
634  }
635 
636  /* init ret code to ssl error */
637  retval = retcode_ssl_err;
638 
639  if((mdctx = EVP_MD_CTX_create()) == NULL) {
640  debug_print("rdm_openssl_file_hash_sha256_pkg_components(): Digest Context Initialize Failed\n");
641  goto error;
642  }
643 
644  if(1 != EVP_DigestInit_ex(mdctx, EVP_sha256(), NULL)) {
645  debug_print("rdm_openssl_file_hash_sha256_pkg_components(): Digest Context Type Setup Failed\n");
646  goto error;
647  }
648 
649  retval = retcode_datafile_err;
650  manifest = calloc(sizeof(char), BUFSIZE);
651  if ( NULL == manifest ) {
652  debug_print("rdm_openssl_file_hash_sha256_pkg_components(): memory allocation failed\n");
653  goto error;
654  }
655  fread(manifest, BUFSIZE, 1, manifest_fh);
656  fclose(manifest_fh);
657  path_buff = strtok(manifest, "\t\r\n");
658  while ( path_buff != NULL )
659  {
660  data_fh = fopen( path_buff, "r" );
661  if( strstr(path_buff, "tmp") || strstr(path_buff, "media") || strstr(path_buff, "padding") || strstr(path_buff, "json") ) {
662  if ( data_fh == NULL ) {
663  printf("rdm_openssl_file_hash_sha256_pkg_components: datafile open error\n");
664  goto error;
665  }
666  bytesread=0;
667  while (1) {
668  bytesread = fread(buffer, 1, BUFSIZE, data_fh );
669  if ( bytesread > 0 ) {
670  if( 1 != EVP_DigestUpdate(mdctx, buffer, bytesread) ) {
671  goto error;
672  }
673  }
674  if ( bytesread != BUFSIZE)
675  break; // EoF found
676  }
677  if ( ferror( data_fh ) ) {
678  goto error;
679  }
680  }
681  path_buff = strtok(NULL, "\t\r\n");
682  if ( data_fh != NULL ) fclose( data_fh );
683  data_fh=NULL;
684  }
685 
686  int hashval_len;
687  if( 1 != EVP_DigestFinal_ex(mdctx, hash_buffer, &hashval_len) ) {
688  goto error;
689  }
690  if ( hashval_len != SHA256_DIGEST_LENGTH ) {
691  goto error;
692  }
693  retval = 0;
694 
695 error:
696 
697  if ( data_fh != NULL ) fclose( data_fh );
698  if ( mdctx != NULL ) EVP_MD_CTX_destroy( mdctx );
699  if ( manifest != NULL) free( manifest );
700  if ( buffer != NULL ) free( buffer );
701  return retval;
702 }
703 
704 /**
705  * @brief This function performs signature verification process.
706  *
707  * @param[in] hashval Hash generated over the data
708  * @param[in] hashval_len Length of hash though we know this all coded to SHA256
709  * @param[in] sig_file Contains the KMS ASCII hex signature ALL UPPER CASE as created by signing process
710  * @param[in] vkey_file PEM format public key exported from KMS
711  * @param[in] reply_msg Buffer to receive message to send to logging system
712  * @param[in] reply_msg_len Pointer to int containing size of buffer. Must be at least 65 bytes.
713  *
714  * @ret returns -1 Bad parameters, including bad length. *buffer_len contains required len.
715  */
716 
717 static
718 int openssl_verify_signature(const unsigned char *hashval, int hashval_len, const char *sig_file, const char *vkey_file, char *reply_msg, int *reply_msg_len)
719 {
720 
721  EVP_MD_CTX *mdctx=NULL;
722  FILE *sig_fh=NULL;
723  EVP_PKEY *pkey=NULL;
724  char hash_ascii[SHA256_ASCII_DIGEST_LENGTH + 1];
725  unsigned char *sig;
726  int sig_len;
727  int retval;
728 
729 
730  /* Only one parameter hasn't been checked by the calling code */
731  if ( hashval == NULL ) {
732  return retcode_param_error;
733  }
734 
735  /**
736  * For no particular reason, decode the signature file first
737  */
738  retval = read_signature_file( sig_file, &sig, &sig_len );
739  if ( retval != 0 ) {
740  debug_print("read_signature_file returns err\n");
741  goto error;
742  }
743 #if defined(DEBUG_ENABLED)
744  dump_buffer( sig, sig_len, "decoded-sig" );
745 #endif
746  size_t hashval_ascii_len = SHA256_ASCII_DIGEST_LENGTH;
747  if ( bin_to_asciihex( hashval, hashval_len, hash_ascii, &hashval_ascii_len ) != 0 ) {
748  debug_print("bin_to_asciihex fail\n");
749  retval = -1;
750  goto error;
751  }
752 
753  /* CAREFUL here - add a 0-terminator. Don't use that trailing 0! */
754  hash_ascii[sizeof(hash_ascii)-1] = 0;
755  debug_print("HASH ASCII (signed message):\n%s\n",hash_ascii);
756 
757  /**
758  * Perform verify operations
759  */
760 
761  /* initialize `key` with a public key */
762  debug_print("reading key file: %s\n",vkey_file);
763  FILE *pub_fh = fopen( vkey_file, "rb" );
764  if ( pub_fh == NULL ) {
765  debug_print( "pubkey open fail\n" );
766  retval = retcode_keyfile_err;
767  goto error;
768  }
769 
770  pkey = PEM_read_PUBKEY( pub_fh, NULL, NULL, NULL );
771  if ( pkey == NULL ) {
772  debug_print( "pubkey read fail\n" );
773  goto error;
774  }
775 
776  /* reinit a digest context */
777  EVP_MD_CTX_destroy( mdctx );
778  if((mdctx = EVP_MD_CTX_create()) == NULL) {
779  debug_print( "verify context create fail\n" );
780  goto error;
781  }
782 
783  /* Initialize verify */
784  if(1 != EVP_DigestVerifyInit(mdctx, NULL, EVP_sha256(), NULL, pkey)) {
785  debug_print( "digest verify init fail\n" );
786  goto err;
787  }
788 
789  /* perform verify */
790  if( 1 != EVP_DigestVerifyUpdate( mdctx, hash_ascii, SHA256_ASCII_DIGEST_LENGTH ) ) {
791  debug_print( "digest verify update fail\n" );
792  goto err;
793  }
794 
795  /* check verify */
796  if(1 == EVP_DigestVerifyFinal( mdctx, sig, sig_len) )
797  {
798  retval = retcode_success;
799  }
800  else
801  {
802  retval = retcode_verify_fail;
803  }
804 err:
805 error:
806 
807  if ( sig_fh != NULL ) fclose( sig_fh );
808  if ( pub_fh != NULL ) fclose( pub_fh );
809  if ( mdctx != NULL ) EVP_MD_CTX_destroy( mdctx );
810  if ( pkey != NULL ) EVP_PKEY_free( pkey );
811 
812  /* other clean here */
813 
814  snprintf( reply_msg, (size_t)REPLY_MSG_LEN, "c_l_s_v performance status: %x", retval );
815  return retval;
816  }
817 
818 
819 
820 /**
821  * @brief This function is used for a signature validation of the package.
822  *
823  * @param[in] data_file Input data file.
824  * @param[in] file_len Input data file length.
825  * @param[in] sig_file Signature file.
826  * @param[in] vkey_file Public key file.
827  * @param[in] reply_msg Return Value.
828  * @param[in] reply_msg_len Length of return value message.
829  *
830  * @return Returns the status of the operation.
831  * @retval -1 On error.
832  * @retval 5 When failed to open public key.
833  * @retval 0 Success on signature verification.
834  * @retval 2 Failure on signature verification.
835  */
836  int rdm_openssl_rsa_file_signature_verify(const char *data_file, size_t file_len, const char *sig_file, const char *vkey_file, char *reply_msg, int *reply_msg_len)
837  {
838  int retval;
839 
840  unsigned char hashval[SHA256_DIGEST_LENGTH];
841  int hashval_len=SHA256_DIGEST_LENGTH;
842 
843  debug_print("Entry: rdm_openssl_rsa_file_signature_verify\n");
844  if ( data_file == NULL ||
845  sig_file == NULL ||
846  reply_msg == NULL ||
847  vkey_file == NULL ||
848  reply_msg_len == NULL ) {
849  debug_print("rdm_openssl_rsa_file_signature_verify(): Input Args parameter error\n");
850  return retcode_param_error;
851  }
852 
853  if ( *reply_msg_len < REPLY_MSG_LEN ) {
854  *reply_msg_len = REPLY_MSG_LEN;
855  debug_print("rdm_openssl_rsa_file_signature_verify(): Output Buffer Len parameter error\n");
856  return retcode_param_error;
857  }
858 
859  if ( NULL == strstr(data_file, "cpemanifest") ) {
860  retval = rdm_openssl_file_hash_sha256( data_file, file_len, hashval, &hashval_len );
861  }
862  else {
863  // Input data file is manifest file having path for all package components
864  printf("rdm_openssl_rsa_file_signature_verify():Initiating signature validation of individual package components\n");
865  retval = rdm_openssl_file_hash_sha256_pkg_components( data_file, file_len, hashval, &hashval_len );
866  }
867  if ( retval != 0 ) {
868  debug_print("rdm_openssl_rsa_file_signature_verify(): rdm_openssl_file_hash_sha256 returns err %x\n",retval);
869  return retval;
870  }
871 
872  retval = openssl_verify_signature(hashval, hashval_len, sig_file, vkey_file, reply_msg, reply_msg_len);
873  return retval;
874 
875  }
876 
877 /** @} */ //END OF GROUP RDM_API
bin_to_asciihex
static int bin_to_asciihex(const unsigned char *bin, size_t bin_length, char *asciihex, size_t *asciihex_length)
This function is used to convert binary data into asciihex format.
Definition: rdm_rsa_signature_verify.c:128
read_signature_file
static int read_signature_file(const char *sig_file, unsigned char **sig_buffer, int *sig_size)
This function decodes the signature file.
Definition: rdm_rsa_signature_verify.c:387
retcode_verify_fail
#define retcode_verify_fail
Definition: rdm_rsa_signature_verify.h:68
retcode_datafile_err
#define retcode_datafile_err
Definition: rdm_rsa_signature_verify.h:65
REPLY_MSG_LEN
#define REPLY_MSG_LEN
Definition: rdm_rsa_signature_verify.h:83
asciihex_to_bin
static int asciihex_to_bin(const char *asciihex, size_t asciihex_length, unsigned char *bin, size_t *bin_length)
This function is used to convert asciihex data into binary format.
Definition: rdm_rsa_signature_verify.c:87
retcode_success
#define retcode_success
Definition: rdm_rsa_signature_verify.h:64
retcode_param_error
#define retcode_param_error
Definition: rdm_rsa_signature_verify.h:63
init_ssl_lib
void init_ssl_lib(void)
This function initializes the openSSL crypto library and configurations.
Definition: rdm_rsa_signature_verify.c:356
retcode_ssl_err
#define retcode_ssl_err
Definition: rdm_rsa_signature_verify.h:67
rdm_signature_verify
int rdm_signature_verify(char *cache_dir, char *app_name, int prepare_files)
This function prepares the rdm files for signature verification and invokes the kms openssl verificat...
Definition: rdm_rsa_signature_verify.c:303
rdm_openssl_file_hash_sha256_pkg_components
static int rdm_openssl_file_hash_sha256_pkg_components(const char *data_file, size_t file_len, unsigned char *hash_buffer, int *buffer_len)
This function is used to initiating signature validation of individual package components.
Definition: rdm_rsa_signature_verify.c:599
rdm_openssl_file_hash_sha256
static int rdm_openssl_file_hash_sha256(const char *data_file, size_t file_len, unsigned char *hash_buffer, int *buffer_len)
This function is used to read and digest the data file.
Definition: rdm_rsa_signature_verify.c:493
retcode_sigfile_err
#define retcode_sigfile_err
Definition: rdm_rsa_signature_verify.h:66
debug_print
#define debug_print(fmt, args...)
Definition: rdm_rsa_signature_verify.h:76
dump_buffer
void dump_buffer(void *buffer, int buffer_size, char *name)
This function outputs all the run's data to stdout and also to a binary file.
Definition: rdm_rsa_signature_verify.c:41
openssl_verify_signature
static int openssl_verify_signature(const unsigned char *hashval, int hashval_len, const char *sig_file, const char *vkey_file, char *reply_msg, int *reply_msg_len)
This function performs signature verification process.
Definition: rdm_rsa_signature_verify.c:718
rdm_openssl_rsa_file_signature_verify
int rdm_openssl_rsa_file_signature_verify(const char *data_file, size_t file_len, const char *sig_file, const char *vkey_file, char *reply_msg, int *reply_msg_len)
This function is used for a signature validation of the package.
Definition: rdm_rsa_signature_verify.c:836
prepare_rdm_files_for_sign_verification
static int prepare_rdm_files_for_sign_verification(char *cache_dir, char *app_name)
This function prepares the rdm files for signature verification Does the following -.
Definition: rdm_rsa_signature_verify.c:237