pdfsig.cc 8.06 KB
Newer Older
1 2
//========================================================================
//
3
// pdfsig.cc
4 5 6 7 8
//
// This file is licensed under the GPLv2 or later
//
// Copyright 2015 André Guerreiro <aguerreiro1985@gmail.com>
// Copyright 2015 André Esser <bepandre@hotmail.com>
9
// Copyright 2015, 2017, 2018 Albert Astals Cid <aacid@kde.org>
10
// Copyright 2016 Markus Kilås <digital@markuspage.com>
11
// Copyright 2017 Hans-Ulrich Jüttner <huj@froreich-bioscientia.de>
12 13
// Copyright 2017 Adrian Johnson <ajohnson@redneon.com>
// Copyright 2018 Chinmoy Ranjan Pradhan <chinmoyrp65@protonmail.com>
14 15 16 17 18 19 20 21 22 23
//
//========================================================================

#include "config.h"
#include <poppler-config.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <time.h>
24
#include <hasht.h>
25
#include <fstream>
26
#include <libgen.h>
27 28 29 30 31 32 33 34
#include "parseargs.h"
#include "Object.h"
#include "Array.h"
#include "Page.h"
#include "PDFDoc.h"
#include "PDFDocFactory.h"
#include "Error.h"
#include "GlobalParams.h"
Albert Astals Cid's avatar
Albert Astals Cid committed
35
#include "SignatureInfo.h"
36
#include "Win32Console.h"
37
#include "numberofcharacters.h"
38

39
static const char * getReadableSigState(SignatureValidationStatus sig_vs)
40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
{
  switch(sig_vs) {
    case SIGNATURE_VALID:
      return "Signature is Valid.";

    case SIGNATURE_INVALID:
      return "Signature is Invalid.";

    case SIGNATURE_DIGEST_MISMATCH:
      return "Digest Mismatch.";

    case SIGNATURE_DECODING_ERROR:
      return "Document isn't signed or corrupted data.";

    case SIGNATURE_NOT_VERIFIED:
      return "Signature has not yet been verified.";

    default:
      return "Unknown Validation Failure.";
  }
}

62
static const char * getReadableCertState(CertificateValidationStatus cert_vs)
63 64 65 66 67
{
  switch(cert_vs) {
    case CERTIFICATE_TRUSTED:
      return "Certificate is Trusted.";

68 69 70 71 72
    case CERTIFICATE_UNTRUSTED_ISSUER:
      return "Certificate issuer isn't Trusted.";

    case CERTIFICATE_UNKNOWN_ISSUER:
      return "Certificate issuer is unknown.";
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87

    case CERTIFICATE_REVOKED:
      return "Certificate has been Revoked.";

    case CERTIFICATE_EXPIRED:
      return "Certificate has Expired";

    case CERTIFICATE_NOT_VERIFIED:
      return "Certificate has not yet been verified.";

    default:
      return "Unknown issue with Certificate or corrupted data.";
  }
}

88
static char *getReadableTime(time_t unix_time)
89 90 91 92 93 94
{
  char * time_str = (char *) gmalloc(64);
  strftime(time_str, 64, "%b %d %Y %H:%M:%S", localtime(&unix_time));
  return time_str;
}

95
static void dumpSignature(int sig_num, int sigCount, FormWidgetSignature *sig_widget, const char *filename)
96 97 98 99 100 101 102
{
    const GooString *signature = sig_widget->getSignature();
    if (!signature) {
        printf("Cannot dump signature #%d\n", sig_num);
        return;
    }

103 104 105 106 107
    const int sigCountLength = numberOfCharacters(sigCount);
    // We want format to be {0:s}.sig{1:Xd} where X is sigCountLength
    // since { is the magic character to replace things we need to put it twice where
    // we don't want it to be replaced
    GooString *format = GooString::format("{{0:s}}.sig{{1:{0:d}d}}", sigCountLength);
108 109 110
    char *filenameCopy = strdup(filename);
    GooString *path = GooString::format(format->getCString(), basename(filenameCopy), sig_num);
    free(filenameCopy);
111 112
    printf("Signature #%d (%u bytes) => %s\n", sig_num, signature->getLength(), path->getCString());
    std::ofstream outfile(path->getCString(), std::ofstream::binary);
113 114
    outfile.write(signature->getCString(), signature->getLength());
    outfile.close();
115 116
    delete format;
    delete path;
117 118
}

119 120 121
static GBool printVersion = gFalse;
static GBool printHelp = gFalse;
static GBool dontVerifyCert = gFalse;
122
static GBool dumpSignatures = gFalse;
123 124

static const ArgDesc argDesc[] = {
125 126
  {"-nocert", argFlag,     &dontVerifyCert,     0,
   "don't perform certificate validation"},
127 128
  {"-dump",   argFlag,     &dumpSignatures,     0,
   "dump all signatures into current directory"},
129

130 131 132 133 134 135
  {"-v",      argFlag,     &printVersion,  0,
   "print copyright and version info"},
  {"-h",      argFlag,     &printHelp,     0,
   "print usage information"},
  {"-help",   argFlag,     &printHelp,     0,
   "print usage information"},
136 137
  {"-?",      argFlag,     &printHelp,     0,
   "print usage information"},
138
  {}
139 140 141 142 143
};


int main(int argc, char *argv[])
{
144
  PDFDoc *doc = nullptr;
145
  unsigned int sigCount;
146 147 148
  GooString * fileName = nullptr;
  SignatureInfo *sig_info = nullptr;
  char *time_str = nullptr;
149 150 151
  std::vector<FormWidgetSignature*> sig_widgets;
  globalParams = new GlobalParams();

152
  Win32Console win32Console(&argc, &argv);
153 154 155 156 157 158
  int exitCode = 99;
  GBool ok;

  ok = parseArgs(argDesc, &argc, argv);

  if (!ok || argc != 2 || printVersion || printHelp) {
159
    fprintf(stderr, "pdfsig version %s\n", PACKAGE_VERSION);
160 161 162
    fprintf(stderr, "%s\n", popplerCopyright);
    fprintf(stderr, "%s\n", xpdfCopyright);
    if (!printVersion) {
163
      printUsage("pdfsig", "<PDF-file>", argDesc);
164 165 166 167 168 169 170 171 172
    }
    if (printVersion || printHelp)
      exitCode = 0;
    goto end;
  }

  fileName = new GooString(argv[argc - 1]);

  // open PDF file
173
  doc = PDFDocFactory().createPDFDoc(*fileName, nullptr, nullptr);
174 175 176

  if (!doc->isOk()) {
    exitCode = 1;
177
    goto end;
178 179
  }

180 181
  sig_widgets = doc->getSignatureWidgets();
  sigCount = sig_widgets.size();
182 183

  if (sigCount >= 1) {
184 185 186
    if (dumpSignatures) {
      printf("Dumping Signatures: %u\n", sigCount);
      for (unsigned int i = 0; i < sigCount; i++) {
187
        dumpSignature(i, sigCount, sig_widgets.at(i), fileName->getCString());
188 189 190 191 192
      }
      goto end;
    } else {
      printf("Digital Signature Info of: %s\n", fileName->getCString());
    }
193 194 195 196 197 198
  } else {
    printf("File '%s' does not contain any signatures\n", fileName->getCString());
    exitCode = 2;
    goto end;
  }

199
  for (unsigned int i = 0; i < sigCount; i++) {
200
    sig_info = sig_widgets.at(i)->validateSignature(!dontVerifyCert, false, -1 /* now */);
201
    printf("Signature #%u:\n", i+1);
202
    printf("  - Signer Certificate Common Name: %s\n", sig_info->getSignerName());
203
    printf("  - Signer full Distinguished Name: %s\n", sig_info->getSubjectDN());
204
    printf("  - Signing Time: %s\n", time_str = getReadableTime(sig_info->getSigningTime()));
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
    printf("  - Signing Hash Algorithm: ");
    switch (sig_info->getHashAlgorithm())
    {
      case HASH_AlgMD2:
        printf("MD2\n");
        break;
      case HASH_AlgMD5:
        printf("MD5\n");
        break;
      case HASH_AlgSHA1:
        printf("SHA1\n");
        break;
      case HASH_AlgSHA256:
        printf("SHA-256\n");
        break;
      case HASH_AlgSHA384:
        printf("SHA-384\n");
        break;
      case HASH_AlgSHA512:
        printf("SHA-512\n");
        break;
      case HASH_AlgSHA224:
        printf("SHA-224\n");
        break;
      default:
        printf("unknown\n");
    }
    printf("  - Signature Type: ");
    switch (sig_widgets.at(i)->signatureType())
    {
      case adbe_pkcs7_sha1:
        printf("adbe.pkcs7.sha1\n");
        break;
      case adbe_pkcs7_detached:
        printf("adbe.pkcs7.detached\n");
        break;
      case ETSI_CAdES_detached:
        printf("ETSI.CAdES.detached\n");
        break;
      default:
        printf("unknown\n");
    }
    std::vector<Goffset> ranges = sig_widgets.at(i)->getSignedRangeBounds();
    if (ranges.size() == 4)
    {
      printf("  - Signed Ranges: [%lld - %lld], [%lld - %lld]\n",
             ranges[0], ranges[1], ranges[2], ranges[3]);
252 253 254
      Goffset checked_file_size;
      GooString* signature = sig_widgets.at(i)->getCheckedSignature(&checked_file_size);
      if (signature && checked_file_size == ranges[3])
255 256 257 258 259 260 261
      {
        printf("  - Total document signed\n");
        delete signature;
      }
      else
        printf("  - Not total document signed\n");
    }
262
    printf("  - Signature Validation: %s\n", getReadableSigState(sig_info->getSignatureValStatus()));
263
    gfree(time_str);
264 265 266 267 268 269 270 271 272 273
    if (sig_info->getSignatureValStatus() != SIGNATURE_VALID || dontVerifyCert) {
      continue;
    }
    printf("  - Certificate Validation: %s\n", getReadableCertState(sig_info->getCertificateValStatus()));
  }

  exitCode = 0;

end:
  delete globalParams;
274 275
  delete fileName;
  delete doc;
276 277 278

  return exitCode;
}