예제 #1
0
char * get_hmac(char * cipher, char * key, size_t length){
	/* Generating hmac from the encrypted content
	GCRY_MD_SHA512 - Algo
	flags or of GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC 
	indicating that its secure mode and we need HMAC
	*/
	gcry_error_t err;
	gcry_md_hd_t hm;
	err = gcry_md_open(&hm, GCRY_MD_SHA512, GCRY_MD_FLAG_SECURE | GCRY_MD_FLAG_HMAC);
	if(err != GPG_ERR_NO_ERROR){
		printf ("Error at opening handle for hmac: %s\n",gcry_strerror(err));
		exit(-1);
	}
	err = gcry_md_enable(hm,GCRY_MD_SHA512);
	err = gcry_md_setkey(hm, key,KEYLENGTH_SHA );
	if(err != GPG_ERR_NO_ERROR){
		printf ("Error at setting key: %s\n",gcry_strerror(err));
		exit(-1);
	}
	// generating the HMAC using the cipher text
  	gcry_md_write(hm,cipher,length);
  	gcry_md_final(hm);
  	// printf("\nlength: %lu\n",length);

	char * hmac;
	hmac = gcry_md_read(hm , GCRY_MD_SHA512 );
	if(hmac == NULL ){
		printf ("hmac null ?\n");
		// exit(-1);
	}
	// print_buf(hmac,64); // debug
	// printf("hmac length : %lu\n",strlen(hmac)); // debug to check hmac length should be 64
	return hmac;
}
예제 #2
0
파일: md.c 프로젝트: IFGHou/AIDE
int init_md(struct md_container* md) {
  
  int i;
  /*    First we check the parameter..   */
#ifdef _PARAMETER_CHECK_
  if (md==NULL) {
    return RETFAIL;  
  }
#endif
  error(255,"init_md called\n");
  /*
    We don't have calculator for this yet :)
  */
  md->calc_attr=0;
#ifdef WITH_MHASH
  error(255,"Mhash library initialization\n");
  for(i=0;i<=HASH_MHASH_COUNT;i++) {
    if (((hash_mhash2attr(i)&HASH_USE_MHASH)&md->todo_attr)!=0) {
      DB_ATTR_TYPE h=hash_mhash2attr(i);
      error(255,"inserting %llu\n",h);
      md->mhash_mdh[i]=mhash_init(i);
      if (md->mhash_mdh[i]!=MHASH_FAILED) {
				md->calc_attr|=h;
      } else {
	/*
	  Oops.. 
	  We just don't calculate this.
	 */

				md->todo_attr&=~h;
      }

    } else {
      md->mhash_mdh[i]=MHASH_FAILED;      
    }
  }
#endif 
#ifdef WITH_GCRYPT
  error(255,"Gcrypt library initialization\n");
  	if(!gcry_check_version(GCRYPT_VERSION)) {
		error(0,"libgcrypt version mismatch\n");
		exit(VERSION_MISMATCH_ERROR);
	}
	gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
	gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
	if(gcry_md_open(&md->mdh,0,0)!=GPG_ERR_NO_ERROR){
		error(0,"gcrypt_md_open failed\n");
		exit(IO_ERROR);
	}
  for(i=0;i<=HASH_GCRYPT_COUNT;i++) {
    if (((hash_gcrypt2attr(i)&HASH_USE_GCRYPT)&md->todo_attr)!=0) {
      DB_ATTR_TYPE h=hash_gcrypt2attr(i);
      error(255,"inserting %llu\n",h);
			if(gcry_md_enable(md->mdh,i)==GPG_ERR_NO_ERROR){
				md->calc_attr|=h;
			} else {
				error(0,"gcry_md_enable %i failed",i);
				md->todo_attr&=~h;
			}
		}
	}
#endif
  return RETOK;
}
예제 #3
0
void decrypt(char *outfile, char *inpfile) {

	gcry_err_code_t err = 0;
	gcry_cipher_hd_t gchandle;
	const int blks = gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES256);
	const int keyl = gcry_cipher_get_algo_keylen(GCRY_CIPHER_AES256);
	long outfileSize = 0;
	char key[keyl];
	const char* salt = "iuyjdbnbtaqonbgt";
	//open output file
	FILE *fout = fopen(outfile, "r");
	if (!fout) {
		printf("output file name : %s\n", outfile);
		fout = fopen(outfile, "w");
	} else {
		printf("Output file already exist on disk.\n");
		return;;
	}
	char password[100];
	do {
		printf("Please enter password between 8-20 chars :");
		scanf("%s", password);
	} while (strlen(password) > 20 || strlen(password) < 8);

	err = gcry_kdf_derive(password, strlen(password), GCRY_KDF_PBKDF2,
			GCRY_MD_SHA256, salt, strlen(salt), 937, keyl, key);
	if (err) {
		fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
				gcry_strerror(err));
		exit(EXIT_FAILURE);
	}

	char ctext[blks];
	char extractedIV[blks];
	FILE *finp = fopen(inpfile, "r");
	fseek(finp, 0, SEEK_SET);
	unsigned char extractedHMAC[keyl + 1];

	fread(extractedHMAC, 1, keyl, finp); //extract HMAC from received file
	extractedHMAC[keyl] = '\0';

	// Compare calculated HMAC with extracted HMAC ---> start
	long cipherSize = 0;
	fseek(finp, 0, SEEK_END);
	cipherSize = ftell(finp) - keyl;
	fseek(finp, keyl, SEEK_SET);
	unsigned char *hmacBuffer = malloc(cipherSize + 1);
	fread(hmacBuffer, 1, cipherSize, finp);
	gcry_md_hd_t hd;
	err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
	if (err) {
		fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
				gcry_strerror(err));
		fclose(finp);
		fclose(fout);
		exit(EXIT_FAILURE);
	}
	err = gcry_md_setkey(hd, key, keyl);
	if (err) {
		fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
				gcry_strerror(err));
		fclose(finp);
		fclose(fout);
		exit(EXIT_FAILURE);
	}
	err = gcry_md_enable(hd, GCRY_MD_SHA256);
	if (err) {
		fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
				gcry_strerror(err));
		fclose(finp);
		fclose(fout);
		exit(EXIT_FAILURE);
	}
	gcry_md_write(hd, hmacBuffer, cipherSize);

	char thmac[keyl];
	unsigned char *hmac = thmac;
	hmac = gcry_md_read(hd, GCRY_MD_SHA256);

	int i = 0;
	int hflag = 1;
	for (; i < keyl; i++) {
		if (hmac[i] != extractedHMAC[i])
			hflag = 0;
	}
	if (hflag)
		printf("HMAC successfully matched\n");
	else
		printf("HMAC not matched\n");

	fseek(finp, keyl, SEEK_SET);
	// Compare calculated HMAC with extracted HMAC ---> end

	//Decryption algo ------> start
	fread(extractedIV, 1, blks, finp); // read IV
	err = gcry_cipher_open(&gchandle, GCRY_CIPHER_AES256, GCRY_CIPHER_MODE_CBC,
			0);
	if (err) {
		fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
				gcry_strerror(err));
		exit(EXIT_FAILURE);
	}

	err = gcry_cipher_setkey(gchandle, key, keyl);
	if (err) {
		fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
				gcry_strerror(err));
		exit(EXIT_FAILURE);
	}
	err = gcry_cipher_setiv(gchandle, extractedIV, blks);
	if (err) {
		fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
				gcry_strerror(err));
		exit(EXIT_FAILURE);
	}

	if (!finp) {
		printf("Could not open input text file\n");
	} else {
		int x = 0;
		char plaintext[blks];
		while ((x = fread(plaintext, 1, blks, finp))) {
			if (x < blks) // add padding to last block
				outfileSize += x;
			err = gcry_cipher_decrypt(gchandle, ctext, blks, plaintext, x);
			if (err && x == blks) {
				fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
						gcry_strerror(err));
				fclose(finp);
				fclose(fout);
				exit(EXIT_FAILURE);
			}
			fwrite(ctext, 1, blks, fout);
		}
		gcry_cipher_close(gchandle);

		gcry_md_close(hd);

		fclose(finp);
		fclose(fout);
	}
	free(hmacBuffer);
	//Decryption algo ------> end
}
예제 #4
0
int main(int argc, char *argv[]) {

	int lflag = 0;
	int dflag = 0;
	int c;

	opterr = 0;
	while ((c = getopt(argc, argv, "dl")) != -1)
		switch (c) {
		case 'd':
			dflag = 1;
			break;
		case 'l':
			lflag = 1;
			break;
		case '?':
			if (isprint (optopt))
				fprintf(stderr, "Unknown option `-%c'.\n", optopt);
			else
				fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt);
			return 1;
		default:
			exit(EXIT_FAILURE);
		}

	if (dflag || lflag) {
		gcry_err_code_t err = 0;
		gcry_cipher_hd_t gchandle;
		const int blks = gcry_cipher_get_algo_blklen(GCRY_CIPHER_AES256);
		const int keyl = gcry_cipher_get_algo_keylen(GCRY_CIPHER_AES256);
		long outfileSize = 0;
		char key[keyl];
		const char* salt = "iuyjdbnbtaqonbgt";
		//open output file
		char outfile[256];
		strcpy(outfile, argv[optind]);
		strncat(outfile, ".uf\0", 4);
		FILE *fout = fopen(outfile, "r");
		if (!fout) {
			//printf("output file name : %s\n", outfile);
			fout = fopen(outfile, "w");
		} else {
			printf("Output file already exist on disk.\n");
			exit(EXIT_FAILURE);
		}
		char password[100];
		do {
			printf("Please enter password between 8-20 chars :");
			scanf("%s", password);
		} while (strlen(password) > 20 || strlen(password) < 8);

		err = gcry_kdf_derive(password, strlen(password), GCRY_KDF_PBKDF2,
				GCRY_MD_SHA256, salt, strlen(salt), 937, keyl, key);
		if (err) {
			fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
					gcry_strerror(err));
			exit(EXIT_FAILURE);
		}

		char ctext[blks];
		char *iv = "1234567890123456";
		fwrite(iv, 1, blks, fout);
		outfileSize += blks;

		// Encryption Algo ----> start
		err = gcry_cipher_open(&gchandle, GCRY_CIPHER_AES256,
				GCRY_CIPHER_MODE_CBC, 0);
		if (err) {
			fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
					gcry_strerror(err));
			exit(EXIT_FAILURE);
		}

		err = gcry_cipher_setkey(gchandle, key, keyl);
		if (err) {
			fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
					gcry_strerror(err));
			exit(EXIT_FAILURE);
		}
		err = gcry_cipher_setiv(gchandle, iv, blks);
		if (err) {
			fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
					gcry_strerror(err));
			exit(EXIT_FAILURE);
		}
		FILE *finp = fopen(argv[optind], "r");
		if (!finp) {
			printf("Could not open text file\n");
		} else {
			int x = 0;
			char plaintext[blks];
			while ((x = fread(plaintext, 1, blks, finp))) {
				if (x < blks) { // add padding to last block
					fseek(finp, 0, SEEK_END);
					for (; x < blks; x++) {
						plaintext[x] = '$';
						fputc('$', finp);
					}
				}

				err = gcry_cipher_encrypt(gchandle, ctext, blks, plaintext, x);
				if (err && x == blks) {
					fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
							gcry_strerror(err));
					fclose(finp);
					fclose(fout);
					exit(EXIT_FAILURE);
				}
				fwrite(ctext, 1, blks, fout);
				outfileSize += blks;
			}
			gcry_cipher_close(gchandle);
			fclose(fout);
			//generating HMAC
			fout = fopen(outfile, "r+");
			fseek(fout, 0, SEEK_SET);
			unsigned char *hmacBuffer = malloc(outfileSize + 1);
			fread(hmacBuffer, 1, outfileSize, fout);
			fseek(fout, 0, SEEK_END);
			fclose(fout);
			gcry_md_hd_t hd;
			err = gcry_md_open(&hd, GCRY_MD_SHA256, GCRY_MD_FLAG_HMAC);
			if (err) {
				fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
						gcry_strerror(err));
				fclose(finp);
				fclose(fout);
				exit(EXIT_FAILURE);
			}
			err = gcry_md_setkey(hd, key, keyl);
			if (err) {
				fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
						gcry_strerror(err));
				fclose(finp);
				fclose(fout);
				exit(EXIT_FAILURE);
			}
			err = gcry_md_enable(hd, GCRY_MD_SHA256);
			if (err) {
				fprintf(stderr, "Failure: %s/%s\n", gcry_strsource(err),
						gcry_strerror(err));
				fclose(finp);
				fclose(fout);
				exit(EXIT_FAILURE);
			}
			gcry_md_write(hd, hmacBuffer, outfileSize);
			char thmac[keyl];
			unsigned char *hmac = thmac;
			hmac = gcry_md_read(hd, GCRY_MD_SHA256);
			//printf("%s\n",hmac);
			//writing file contents as hmac(32 byte) + iv(16 byte) + cipher
			fout = fopen(outfile, "w");
			fwrite(hmac, 1, keyl, fout);
			fwrite(hmacBuffer, 1, outfileSize, fout);
			gcry_md_close(hd);
			fclose(finp);
			fclose(fout);
			free(hmacBuffer);
			// Encryption Algo ----> end
		}

		/* Transferring file over ip */
		if (dflag) {
			int client_socket;
			ssize_t len;
			struct sockaddr_in server_addr;
			int fd;
			int sent_bytes = 0;
			char file_size[256];
			struct stat file_stat;
			int offset;
			int remain_data;
			char ip[15], port[4];

			int i = 0, j = 0;
			for (; argv[optind + 1][i] != ':'; i++) {
				ip[i] = argv[optind + 1][i];
			}
			i++;
			for (; i < strlen(argv[optind + 1]); i++, j++) {
				port[j] = argv[optind + 1][i];
			}

			/* Create client socket */
			client_socket = socket(AF_INET, SOCK_STREAM, 0);
			if (client_socket == -1) {
				fprintf(stderr, "Error creating socket --> %s",
						strerror(errno));

				exit(EXIT_FAILURE);
			}

			/* Zeroing server_addr struct */
			memset(&server_addr, 0, sizeof(server_addr));
			/* Construct server_addr struct */
			server_addr.sin_family = AF_INET;
			inet_pton(AF_INET, ip, &(server_addr.sin_addr));
			server_addr.sin_port = htons(atoi(port));

			/* Connect to the server */
			if (connect(client_socket, (struct sockaddr *) &server_addr,
					sizeof(struct sockaddr)) == -1) {
				fprintf(stderr, "Error on connect --> %s\n", strerror(errno));

				exit(EXIT_FAILURE);
			}
			fd = open(outfile, O_RDONLY);
			if (fd == -1) {
				fprintf(stderr, "Error opening file --> %s", strerror(errno));

				exit(EXIT_FAILURE);
			}

			/* Get file stats */
			if (fstat(fd, &file_stat) < 0) {
				fprintf(stderr, "Error fstat --> %s", strerror(errno));

				exit(EXIT_FAILURE);
			}

			fprintf(stdout, "File Size: \n%ld bytes\n", file_stat.st_size);

			sprintf(file_size, "%d", file_stat.st_size);

			/* Sending file size */
			len = send(client_socket, file_size, sizeof(file_size), 0);
			if (len < 0) {
				fprintf(stderr, "Error on sending greetings --> %s",
						strerror(errno));

				exit(EXIT_FAILURE);
			}
			fprintf(stdout, "Client sent %ld bytes for the size\n", len);
			/* Sending file name */
			len = send(client_socket, outfile, sizeof(outfile), 0);
			if (len < 0) {
				fprintf(stderr, "Error on sending greetings --> %s",
						strerror(errno));

				exit(EXIT_FAILURE);
			}
			fprintf(stdout, "Client sent %ld bytes for the filename: %s\n", len,
					outfile);
			offset = 0;
			remain_data = file_stat.st_size;
			/* Sending file data */
			while (((sent_bytes = sendfile(client_socket, fd, &offset, BUFSIZ))
					> 0) && (remain_data > 0)) {
				fprintf(stdout,
						"1. Client sent %d bytes from file's data, offset is now : %d and remaining data = %d\n",
						sent_bytes, offset, remain_data);
				remain_data -= sent_bytes;
				fprintf(stdout,
						"2. Client sent %d bytes from file's data, offset is now : %d and remaining data = %d\n",
						sent_bytes, offset, remain_data);
			}
			close(client_socket);

		}
	}
	return EXIT_SUCCESS;
}
예제 #5
0
파일: verify.c 프로젝트: GroovIM/transport
/* Perform a verify operation.  To verify detached signatures, data_fd
   must be different than -1.  With OUT_FP given and a non-detached
   signature, the signed material is written to that stream. */
int
gpgsm_verify (ctrl_t ctrl, int in_fd, int data_fd, FILE *out_fp)
{
  int i, rc;
  Base64Context b64reader = NULL;
  Base64Context b64writer = NULL;
  ksba_reader_t reader;
  ksba_writer_t writer = NULL;
  ksba_cms_t cms = NULL;
  ksba_stop_reason_t stopreason;
  ksba_cert_t cert;
  KEYDB_HANDLE kh;
  gcry_md_hd_t data_md = NULL;
  int signer;
  const char *algoid;
  int algo;
  int is_detached;
  FILE *fp = NULL;
  char *p;

  audit_set_type (ctrl->audit, AUDIT_TYPE_VERIFY);

  kh = keydb_new (0);
  if (!kh)
    {
      log_error (_("failed to allocated keyDB handle\n"));
      rc = gpg_error (GPG_ERR_GENERAL);
      goto leave;
    }


  fp = fdopen ( dup (in_fd), "rb");
  if (!fp)
    {
      rc = gpg_error (gpg_err_code_from_errno (errno));
      log_error ("fdopen() failed: %s\n", strerror (errno));
      goto leave;
    }

  rc = gpgsm_create_reader (&b64reader, ctrl, fp, 0, &reader);
  if (rc)
    {
      log_error ("can't create reader: %s\n", gpg_strerror (rc));
      goto leave;
    }

  if (out_fp)
    {
      rc = gpgsm_create_writer (&b64writer, ctrl, out_fp, NULL, &writer);
      if (rc)
        {
          log_error ("can't create writer: %s\n", gpg_strerror (rc));
          goto leave;
        }
    }

  rc = ksba_cms_new (&cms);
  if (rc)
    goto leave;

  rc = ksba_cms_set_reader_writer (cms, reader, writer);
  if (rc)
    {
      log_error ("ksba_cms_set_reader_writer failed: %s\n",
                 gpg_strerror (rc));
      goto leave;
    }

  rc = gcry_md_open (&data_md, 0, 0);
  if (rc)
    {
      log_error ("md_open failed: %s\n", gpg_strerror (rc));
      goto leave;
    }
  if (DBG_HASHING)
    gcry_md_start_debug (data_md, "vrfy.data");

  audit_log (ctrl->audit, AUDIT_SETUP_READY);

  is_detached = 0;
  do 
    {
      rc = ksba_cms_parse (cms, &stopreason);
      if (rc)
        {
          log_error ("ksba_cms_parse failed: %s\n", gpg_strerror (rc));
          goto leave;
        }

      if (stopreason == KSBA_SR_NEED_HASH)
        {
          is_detached = 1;
          audit_log (ctrl->audit, AUDIT_DETACHED_SIGNATURE);
          if (opt.verbose)
            log_info ("detached signature\n");
        }

      if (stopreason == KSBA_SR_NEED_HASH
          || stopreason == KSBA_SR_BEGIN_DATA)
        { 
          audit_log (ctrl->audit, AUDIT_GOT_DATA);

          /* We are now able to enable the hash algorithms */
          for (i=0; (algoid=ksba_cms_get_digest_algo_list (cms, i)); i++)
            {
              algo = gcry_md_map_name (algoid);
              if (!algo)
                {
                  log_error ("unknown hash algorithm `%s'\n",
                             algoid? algoid:"?");
                  if (algoid
                      && (  !strcmp (algoid, "1.2.840.113549.1.1.2")
                          ||!strcmp (algoid, "1.2.840.113549.2.2")))
                    log_info (_("(this is the MD2 algorithm)\n"));
                  audit_log_s (ctrl->audit, AUDIT_BAD_DATA_HASH_ALGO, algoid);
                }
              else
                {
                  if (DBG_X509)
                    log_debug ("enabling hash algorithm %d (%s)\n",
                               algo, algoid? algoid:"");
                  gcry_md_enable (data_md, algo);
                  audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);
                }
            }
          if (opt.extra_digest_algo)
            {
              if (DBG_X509)
                log_debug ("enabling extra hash algorithm %d\n", 
                           opt.extra_digest_algo);
              gcry_md_enable (data_md, opt.extra_digest_algo);
              audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO,
                           opt.extra_digest_algo);
            }
          if (is_detached)
            {
              if (data_fd == -1)
                {
                  log_info ("detached signature w/o data "
                            "- assuming certs-only\n");
                  audit_log (ctrl->audit, AUDIT_CERT_ONLY_SIG);
                }
              else
                audit_log_ok (ctrl->audit, AUDIT_DATA_HASHING,
                              hash_data (data_fd, data_md));
            }
          else
            {
              ksba_cms_set_hash_function (cms, HASH_FNC, data_md);
            }
        }
      else if (stopreason == KSBA_SR_END_DATA)
        { /* The data bas been hashed */
          audit_log_ok (ctrl->audit, AUDIT_DATA_HASHING, 0);
        }
    }
  while (stopreason != KSBA_SR_READY);   

  if (b64writer)
    {
      rc = gpgsm_finish_writer (b64writer);
      if (rc) 
        {
          log_error ("write failed: %s\n", gpg_strerror (rc));
          audit_log_ok (ctrl->audit, AUDIT_WRITE_ERROR, rc);
          goto leave;
        }
    }

  if (data_fd != -1 && !is_detached)
    {
      log_error ("data given for a non-detached signature\n");
      rc = gpg_error (GPG_ERR_CONFLICT);
      audit_log (ctrl->audit, AUDIT_USAGE_ERROR);
      goto leave;
    }

  for (i=0; (cert=ksba_cms_get_cert (cms, i)); i++)
    {
      /* Fixme: it might be better to check the validity of the
         certificate first before entering it into the DB.  This way
         we would avoid cluttering the DB with invalid
         certificates. */
      audit_log_cert (ctrl->audit, AUDIT_SAVE_CERT, cert, 
                      keydb_store_cert (cert, 0, NULL));
      ksba_cert_release (cert);
    }

  cert = NULL;
  for (signer=0; ; signer++)
    {
      char *issuer = NULL;
      ksba_sexp_t sigval = NULL;
      ksba_isotime_t sigtime, keyexptime;
      ksba_sexp_t serial;
      char *msgdigest = NULL;
      size_t msgdigestlen;
      char *ctattr;
      int sigval_hash_algo;
      int info_pkalgo;
      unsigned int verifyflags;

      rc = ksba_cms_get_issuer_serial (cms, signer, &issuer, &serial);
      if (!signer && gpg_err_code (rc) == GPG_ERR_NO_DATA
          && data_fd == -1 && is_detached)
        {
          log_info ("certs-only message accepted\n");
          rc = 0;
          break;
        }
      if (rc)
        {
          if (signer && rc == -1)
            rc = 0;
          break;
        }

      gpgsm_status (ctrl, STATUS_NEWSIG, NULL);
      audit_log_i (ctrl->audit, AUDIT_NEW_SIG, signer);

      if (DBG_X509)
        {
          log_debug ("signer %d - issuer: `%s'\n",
                     signer, issuer? issuer:"[NONE]");
          log_debug ("signer %d - serial: ", signer);
          gpgsm_dump_serial (serial);
          log_printf ("\n");
        }
      if (ctrl->audit)
        {
          char *tmpstr = gpgsm_format_sn_issuer (serial, issuer);
          audit_log_s (ctrl->audit, AUDIT_SIG_NAME, tmpstr);
          xfree (tmpstr);
        }

      rc = ksba_cms_get_signing_time (cms, signer, sigtime);
      if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
        *sigtime = 0;
      else if (rc)
        {
          log_error ("error getting signing time: %s\n", gpg_strerror (rc));
          *sigtime = 0; /* (we can't encode an error in the time string.) */
        }

      rc = ksba_cms_get_message_digest (cms, signer,
                                        &msgdigest, &msgdigestlen);
      if (!rc)
        {
          size_t is_enabled;

          algoid = ksba_cms_get_digest_algo (cms, signer);
          algo = gcry_md_map_name (algoid);
          if (DBG_X509)
            log_debug ("signer %d - digest algo: %d\n", signer, algo);
          is_enabled = sizeof algo;
          if ( gcry_md_info (data_md, GCRYCTL_IS_ALGO_ENABLED,
                             &algo, &is_enabled)
               || !is_enabled)
            {
              log_error ("digest algo %d (%s) has not been enabled\n", 
                         algo, algoid?algoid:"");
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "unsupported");
              goto next_signer;
            }
        }
      else if (gpg_err_code (rc) == GPG_ERR_NO_DATA)
        {
          assert (!msgdigest);
          rc = 0;
          algoid = NULL;
          algo = 0; 
        }
      else /* real error */
        {
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
          break;
        }

      rc = ksba_cms_get_sigattr_oids (cms, signer,
                                      "1.2.840.113549.1.9.3", &ctattr);
      if (!rc) 
        {
          const char *s;

          if (DBG_X509)
            log_debug ("signer %d - content-type attribute: %s",
                       signer, ctattr);

          s = ksba_cms_get_content_oid (cms, 1);
          if (!s || strcmp (ctattr, s))
            {
              log_error ("content-type attribute does not match "
                         "actual content-type\n");
              ksba_free (ctattr);
              ctattr = NULL;
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
              goto next_signer;
            }
          ksba_free (ctattr);
          ctattr = NULL;
        }
      else if (rc != -1)
        {
          log_error ("error getting content-type attribute: %s\n",
                     gpg_strerror (rc));
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
          goto next_signer;
        }
      rc = 0;


      sigval = ksba_cms_get_sig_val (cms, signer);
      if (!sigval)
        {
          log_error ("no signature value available\n");
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
          goto next_signer;
        }
      sigval_hash_algo = hash_algo_from_sigval (sigval);
      if (DBG_X509)
        {
          log_debug ("signer %d - signature available (sigval hash=%d)",
                     signer, sigval_hash_algo);
/*           log_printhex ("sigval    ", sigval, */
/*                         gcry_sexp_canon_len (sigval, 0, NULL, NULL)); */
        }
      if (!sigval_hash_algo)
        sigval_hash_algo = algo; /* Fallback used e.g. with old libksba. */

      /* Find the certificate of the signer */
      keydb_search_reset (kh);
      rc = keydb_search_issuer_sn (kh, issuer, serial);
      if (rc)
        {
          if (rc == -1)
            {
              log_error ("certificate not found\n");
              rc = gpg_error (GPG_ERR_NO_PUBKEY);
            }
          else
            log_error ("failed to find the certificate: %s\n",
                       gpg_strerror(rc));
          {
            char numbuf[50];
            sprintf (numbuf, "%d", rc);

            gpgsm_status2 (ctrl, STATUS_ERROR, "verify.findkey",
                           numbuf, NULL);
          }
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "no-cert");
          goto next_signer;
        }

      rc = keydb_get_cert (kh, &cert);
      if (rc)
        {
          log_error ("failed to get cert: %s\n", gpg_strerror (rc));
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
          goto next_signer;
        }

      log_info (_("Signature made "));
      if (*sigtime)
        dump_isotime (sigtime);
      else
        log_printf (_("[date not given]"));
      log_printf (_(" using certificate ID 0x%08lX\n"),
                  gpgsm_get_short_fingerprint (cert, NULL));

      audit_log_i (ctrl->audit, AUDIT_DATA_HASH_ALGO, algo);

      if (msgdigest)
        { /* Signed attributes are available. */
          gcry_md_hd_t md;
          unsigned char *s;

          /* Check that the message digest in the signed attributes
             matches the one we calculated on the data.  */
          s = gcry_md_read (data_md, algo);
          if ( !s || !msgdigestlen
               || gcry_md_get_algo_dlen (algo) != msgdigestlen
               || !s || memcmp (s, msgdigest, msgdigestlen) )
            {
              char *fpr;

              log_error (_("invalid signature: message digest attribute "
                           "does not match computed one\n"));
              if (DBG_X509)
                {
                  if (msgdigest)
                    log_printhex ("message:  ", msgdigest, msgdigestlen);
                  if (s)
                    log_printhex ("computed: ",
                                  s, gcry_md_get_algo_dlen (algo));
                }
              fpr = gpgsm_fpr_and_name_for_status (cert);
              gpgsm_status (ctrl, STATUS_BADSIG, fpr);
              xfree (fpr);
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
              goto next_signer; 
            }
            
          audit_log_i (ctrl->audit, AUDIT_ATTR_HASH_ALGO, sigval_hash_algo);
          rc = gcry_md_open (&md, sigval_hash_algo, 0);
          if (rc)
            {
              log_error ("md_open failed: %s\n", gpg_strerror (rc));
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
              goto next_signer;
            }
          if (DBG_HASHING)
            gcry_md_start_debug (md, "vrfy.attr");

          ksba_cms_set_hash_function (cms, HASH_FNC, md);
          rc = ksba_cms_hash_signed_attrs (cms, signer);
          if (rc)
            {
              log_error ("hashing signed attrs failed: %s\n",
                         gpg_strerror (rc));
              gcry_md_close (md);
              audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "error");
              goto next_signer;
            }
          rc = gpgsm_check_cms_signature (cert, sigval, md, 
                                          sigval_hash_algo, &info_pkalgo);
          gcry_md_close (md);
        }
      else
        {
          rc = gpgsm_check_cms_signature (cert, sigval, data_md, 
                                          algo, &info_pkalgo);
        }

      if (rc)
        {
          char *fpr;

          log_error ("invalid signature: %s\n", gpg_strerror (rc));
          fpr = gpgsm_fpr_and_name_for_status (cert);
          gpgsm_status (ctrl, STATUS_BADSIG, fpr);
          xfree (fpr);
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
          goto next_signer;
        }
      rc = gpgsm_cert_use_verify_p (cert); /*(this displays an info message)*/
      if (rc)
        {
          gpgsm_status_with_err_code (ctrl, STATUS_ERROR, "verify.keyusage",
                                      gpg_err_code (rc));
          rc = 0;
        }

      if (DBG_X509)
        log_debug ("signature okay - checking certs\n");
      audit_log (ctrl->audit, AUDIT_VALIDATE_CHAIN);
      rc = gpgsm_validate_chain (ctrl, cert,
                                 *sigtime? sigtime : "19700101T000000",
                                 keyexptime, 0, 
                                 NULL, 0, &verifyflags);
      {
        char *fpr, *buf, *tstr;

        fpr = gpgsm_fpr_and_name_for_status (cert);
        if (gpg_err_code (rc) == GPG_ERR_CERT_EXPIRED)
          {
            gpgsm_status (ctrl, STATUS_EXPKEYSIG, fpr);
            rc = 0;
          }
        else
          gpgsm_status (ctrl, STATUS_GOODSIG, fpr);
        
        xfree (fpr);

        fpr = gpgsm_get_fingerprint_hexstring (cert, GCRY_MD_SHA1);
        tstr = strtimestamp_r (sigtime);
        buf = xasprintf ("%s %s %s %s 0 0 %d %d 00", fpr, tstr,
                         *sigtime? sigtime : "0",
                         *keyexptime? keyexptime : "0",
                         info_pkalgo, algo);
        xfree (tstr);
        xfree (fpr);
        gpgsm_status (ctrl, STATUS_VALIDSIG, buf);
        xfree (buf);
      }

      audit_log_ok (ctrl->audit, AUDIT_CHAIN_STATUS, rc);
      if (rc) /* of validate_chain */
        {
          log_error ("invalid certification chain: %s\n", gpg_strerror (rc));
          if (gpg_err_code (rc) == GPG_ERR_BAD_CERT_CHAIN
              || gpg_err_code (rc) == GPG_ERR_BAD_CERT
              || gpg_err_code (rc) == GPG_ERR_BAD_CA_CERT
              || gpg_err_code (rc) == GPG_ERR_CERT_REVOKED)
            gpgsm_status_with_err_code (ctrl, STATUS_TRUST_NEVER, NULL,
                                        gpg_err_code (rc));
          else
            gpgsm_status_with_err_code (ctrl, STATUS_TRUST_UNDEFINED, NULL, 
                                        gpg_err_code (rc));
          audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "bad");
          goto next_signer;
        }

      audit_log_s (ctrl->audit, AUDIT_SIG_STATUS, "good");

      for (i=0; (p = ksba_cert_get_subject (cert, i)); i++)
        {
          log_info (!i? _("Good signature from")
                      : _("                aka"));
          log_printf (" \"");
          gpgsm_print_name (log_get_stream (), p);
          log_printf ("\"\n");
          ksba_free (p);
        }

      /* Print a note if this is a qualified signature.  */
      {
        size_t qualbuflen;
        char qualbuffer[1];
        
        rc = ksba_cert_get_user_data (cert, "is_qualified", &qualbuffer,
                                      sizeof (qualbuffer), &qualbuflen);
        if (!rc && qualbuflen)
          {
            if (*qualbuffer)
              {
                log_info (_("This is a qualified signature\n"));
                if (!opt.qualsig_approval)
                  log_info 
                    (_("Note, that this software is not officially approved "
                       "to create or verify such signatures.\n"));
              }
          }    
        else if (gpg_err_code (rc) != GPG_ERR_NOT_FOUND)
          log_error ("get_user_data(is_qualified) failed: %s\n",
                     gpg_strerror (rc)); 
      }

      gpgsm_status (ctrl, STATUS_TRUST_FULLY, 
                    (verifyflags & VALIDATE_FLAG_CHAIN_MODEL)?
                    "0 chain": "0 shell");
          

    next_signer:
      rc = 0;
      xfree (issuer);
      xfree (serial);
      xfree (sigval);
      xfree (msgdigest);
      ksba_cert_release (cert);
      cert = NULL;
    }
  rc = 0;

 leave:
  ksba_cms_release (cms);
  gpgsm_destroy_reader (b64reader);
  gpgsm_destroy_writer (b64writer);
  keydb_release (kh); 
  gcry_md_close (data_md);
  if (fp)
    fclose (fp);

  if (rc)
    {
      char numbuf[50];
      sprintf (numbuf, "%d", rc );
      gpgsm_status2 (ctrl, STATUS_ERROR, "verify.leave",
                     numbuf, NULL);
    }

  return rc;
}