1 49 package com.lowagie.text.pdf; 50 51 import java.io.EOFException ; 52 import java.io.File ; 53 import java.io.IOException ; 54 import java.io.InputStream ; 55 import java.io.OutputStream ; 56 import java.io.RandomAccessFile ; 57 import java.security.PrivateKey ; 58 import java.security.cert.CRL ; 59 import java.security.cert.Certificate ; 60 import java.security.cert.X509Certificate ; 61 import java.text.SimpleDateFormat ; 62 import java.util.ArrayList ; 63 import java.util.Arrays ; 64 import java.util.Calendar ; 65 import java.util.GregorianCalendar ; 66 import java.util.HashMap ; 67 import java.util.Iterator ; 68 import java.util.Map ; 69 70 import com.lowagie.text.Chunk; 71 import com.lowagie.text.DocumentException; 72 import com.lowagie.text.Element; 73 import com.lowagie.text.ExceptionConverter; 74 import com.lowagie.text.Font; 75 import com.lowagie.text.Image; 76 import com.lowagie.text.Paragraph; 77 import com.lowagie.text.Phrase; 78 import com.lowagie.text.Rectangle; 79 80 83 public class PdfSignatureAppearance { 84 85 88 public static final int SignatureRenderDescription = 0; 89 92 public static final int SignatureRenderNameAndDescription = 1; 93 96 public static final int SignatureRenderGraphicAndDescription = 2; 97 98 101 public static final PdfName SELF_SIGNED = PdfName.ADOBE_PPKLITE; 102 105 public static final PdfName VERISIGN_SIGNED = PdfName.VERISIGN_PPKVS; 106 109 public static final PdfName WINCER_SIGNED = PdfName.ADOBE_PPKMS; 110 111 public static final int NOT_CERTIFIED = 0; 112 public static final int CERTIFIED_NO_CHANGES_ALLOWED = 1; 113 public static final int CERTIFIED_FORM_FILLING = 2; 114 public static final int CERTIFIED_FORM_FILLING_AND_ANNOTATIONS = 3; 115 116 private static final float TOP_SECTION = 0.3f; 117 private static final float MARGIN = 2; 118 private Rectangle rect; 119 private Rectangle pageRect; 120 private PdfTemplate app[] = new PdfTemplate[5]; 121 private PdfTemplate frm; 122 private PdfStamperImp writer; 123 private String layer2Text; 124 private String reason; 125 private String location; 126 private Calendar signDate; 127 private String provider; 128 private int page = 1; 129 private String fieldName; 130 private PrivateKey privKey; 131 private Certificate [] certChain; 132 private CRL [] crlList; 133 private PdfName filter; 134 private boolean newField; 135 private ByteBuffer sigout; 136 private OutputStream originalout; 137 private File tempFile; 138 private PdfDictionary cryptoDictionary; 139 private PdfStamper stamper; 140 private boolean preClosed = false; 141 private PdfSigGenericPKCS sigStandard; 142 private int range[]; 143 private RandomAccessFile raf; 144 private byte bout[]; 145 private int boutLen; 146 private byte externalDigest[]; 147 private byte externalRSAdata[]; 148 private String digestEncryptionAlgorithm; 149 private HashMap exclusionLocations; 150 151 PdfSignatureAppearance(PdfStamperImp writer) { 152 this.writer = writer; 153 signDate = new GregorianCalendar (); 154 fieldName = getNewSigName(); 155 } 156 157 private int render = SignatureRenderDescription; 158 159 163 public int getRender() { 164 return render; 165 } 166 167 174 public void setRender(int render) { 175 this.render = render; 176 } 177 178 private Image signatureGraphic = null; 179 180 184 public Image getSignatureGraphic() { 185 return signatureGraphic; 186 } 187 188 193 public void setSignatureGraphic(Image signatureGraphic) { 194 this.signatureGraphic = signatureGraphic; 195 } 196 197 202 public void setLayer2Text(String text) { 203 layer2Text = text; 204 } 205 206 210 public String getLayer2Text() { 211 return layer2Text; 212 } 213 214 219 public void setLayer4Text(String text) { 220 layer4Text = text; 221 } 222 223 227 public String getLayer4Text() { 228 return layer4Text; 229 } 230 231 236 public Rectangle getRect() { 237 return rect; 238 } 239 240 244 public boolean isInvisible() { 245 return (rect == null || rect.getWidth() == 0 || rect.getHeight() == 0); 246 } 247 248 255 public void setCrypto(PrivateKey privKey, Certificate [] certChain, CRL [] crlList, PdfName filter) { 256 this.privKey = privKey; 257 this.certChain = certChain; 258 this.crlList = crlList; 259 this.filter = filter; 260 } 261 262 268 public void setVisibleSignature(Rectangle pageRect, int page, String fieldName) { 269 if (fieldName != null) { 270 if (fieldName.indexOf('.') >= 0) 271 throw new IllegalArgumentException ("Field names cannot contain a dot."); 272 AcroFields af = writer.getAcroFields(); 273 AcroFields.Item item = af.getFieldItem(fieldName); 274 if (item != null) 275 throw new IllegalArgumentException ("The field " + fieldName + " already exists."); 276 this.fieldName = fieldName; 277 } 278 if (page < 1 || page > writer.reader.getNumberOfPages()) 279 throw new IllegalArgumentException ("Invalid page number: " + page); 280 this.pageRect = new Rectangle(pageRect); 281 this.pageRect.normalize(); 282 rect = new Rectangle(this.pageRect.getWidth(), this.pageRect.getHeight()); 283 this.page = page; 284 newField = true; 285 } 286 287 291 public void setVisibleSignature(String fieldName) { 292 AcroFields af = writer.getAcroFields(); 293 AcroFields.Item item = af.getFieldItem(fieldName); 294 if (item == null) 295 throw new IllegalArgumentException ("The field " + fieldName + " does not exist."); 296 PdfDictionary merged = (PdfDictionary)item.merged.get(0); 297 if (!PdfName.SIG.equals(PdfReader.getPdfObject(merged.get(PdfName.FT)))) 298 throw new IllegalArgumentException ("The field " + fieldName + " is not a signature field."); 299 this.fieldName = fieldName; 300 PdfArray r = (PdfArray)PdfReader.getPdfObject(merged.get(PdfName.RECT)); 301 ArrayList ar = r.getArrayList(); 302 float llx = ((PdfNumber)PdfReader.getPdfObject((PdfObject)ar.get(0))).floatValue(); 303 float lly = ((PdfNumber)PdfReader.getPdfObject((PdfObject)ar.get(1))).floatValue(); 304 float urx = ((PdfNumber)PdfReader.getPdfObject((PdfObject)ar.get(2))).floatValue(); 305 float ury = ((PdfNumber)PdfReader.getPdfObject((PdfObject)ar.get(3))).floatValue(); 306 pageRect = new Rectangle(llx, lly, urx, ury); 307 pageRect.normalize(); 308 page = ((Integer )item.page.get(0)).intValue(); 309 int rotation = writer.reader.getPageRotation(page); 310 Rectangle pageSize = writer.reader.getPageSizeWithRotation(page); 311 switch (rotation) { 312 case 90: 313 pageRect = new Rectangle( 314 pageRect.getBottom(), 315 pageSize.getTop() - pageRect.getLeft(), 316 pageRect.getTop(), 317 pageSize.getTop() - pageRect.getRight()); 318 break; 319 case 180: 320 pageRect = new Rectangle( 321 pageSize.getRight() - pageRect.getLeft(), 322 pageSize.getTop() - pageRect.getBottom(), 323 pageSize.getRight() - pageRect.getRight(), 324 pageSize.getTop() - pageRect.getTop()); 325 break; 326 case 270: 327 pageRect = new Rectangle( 328 pageSize.getRight() - pageRect.getBottom(), 329 pageRect.getLeft(), 330 pageSize.getRight() - pageRect.getTop(), 331 pageRect.getRight()); 332 break; 333 } 334 if (rotation != 0) 335 pageRect.normalize(); 336 rect = new Rectangle(this.pageRect.getWidth(), this.pageRect.getHeight()); 337 } 338 339 347 public PdfTemplate getLayer(int layer) { 348 if (layer < 0 || layer >= app.length) 349 return null; 350 PdfTemplate t = app[layer]; 351 if (t == null) { 352 t = app[layer] = new PdfTemplate(writer); 353 t.setBoundingBox(rect); 354 writer.addDirectTemplateSimple(t, new PdfName("n" + layer)); 355 } 356 return t; 357 } 358 359 366 public PdfTemplate getTopLayer() { 367 if (frm == null) { 368 frm = new PdfTemplate(writer); 369 frm.setBoundingBox(rect); 370 writer.addDirectTemplateSimple(frm, new PdfName("FRM")); 371 } 372 return frm; 373 } 374 375 383 public PdfTemplate getAppearance() throws DocumentException { 384 if (isInvisible()) { 385 PdfTemplate t = new PdfTemplate(writer); 386 t.setBoundingBox(new Rectangle(0, 0)); 387 writer.addDirectTemplateSimple(t, null); 388 return t; 389 } 390 if (app[0] == null) { 391 PdfTemplate t = app[0] = new PdfTemplate(writer); 392 t.setBoundingBox(new Rectangle(100, 100)); 393 writer.addDirectTemplateSimple(t, new PdfName("n0")); 394 t.setLiteral("% DSBlank\n"); 395 } 396 if (app[1] == null && !acro6Layers) { 397 PdfTemplate t = app[1] = new PdfTemplate(writer); 398 t.setBoundingBox(new Rectangle(100, 100)); 399 writer.addDirectTemplateSimple(t, new PdfName("n1")); 400 t.setLiteral(questionMark); 401 } 402 if (app[2] == null) { 403 String text; 404 if (layer2Text == null) { 405 StringBuffer buf = new StringBuffer (); 406 buf.append("Digitally signed by ").append(PdfPKCS7.getSubjectFields((X509Certificate )certChain[0]).getField("CN")).append('\n'); 407 SimpleDateFormat sd = new SimpleDateFormat ("yyyy.MM.dd HH:mm:ss z"); 408 buf.append("Date: ").append(sd.format(signDate.getTime())); 409 if (reason != null) 410 buf.append('\n').append("Reason: ").append(reason); 411 if (location != null) 412 buf.append('\n').append("Location: ").append(location); 413 text = buf.toString(); 414 } 415 else 416 text = layer2Text; 417 PdfTemplate t = app[2] = new PdfTemplate(writer); 418 t.setBoundingBox(rect); 419 writer.addDirectTemplateSimple(t, new PdfName("n2")); 420 if (image != null) { 421 if (imageScale == 0) { 422 t.addImage(image, rect.getWidth(), 0, 0, rect.getHeight(), 0, 0); 423 } 424 else { 425 float usableScale = imageScale; 426 if (imageScale < 0) 427 usableScale = Math.min(rect.getWidth() / image.getWidth(), rect.getHeight() / image.getHeight()); 428 float w = image.getWidth() * usableScale; 429 float h = image.getHeight() * usableScale; 430 float x = (rect.getWidth() - w) / 2; 431 float y = (rect.getHeight() - h) / 2; 432 t.addImage(image, w, 0, 0, h, x, y); 433 } 434 } 435 Font font; 436 if (layer2Font == null) 437 font = new Font(); 438 else 439 font = new Font(layer2Font); 440 float size = font.getSize(); 441 442 Rectangle dataRect = null; 443 Rectangle signatureRect = null; 444 445 if (render == SignatureRenderNameAndDescription || 446 (render == SignatureRenderGraphicAndDescription && this.signatureGraphic != null)) { 447 signatureRect = new Rectangle( 449 MARGIN, 450 MARGIN, 451 rect.getWidth() / 2 - MARGIN, 452 rect.getHeight() - MARGIN); 453 dataRect = new Rectangle( 454 rect.getWidth() / 2 + MARGIN / 2, 455 MARGIN, 456 rect.getWidth() - MARGIN / 2, 457 rect.getHeight() - MARGIN); 458 459 if (rect.getHeight() > rect.getWidth()) { 460 signatureRect = new Rectangle( 461 MARGIN, 462 rect.getHeight() / 2, 463 rect.getWidth() - MARGIN, 464 rect.getHeight()); 465 dataRect = new Rectangle( 466 MARGIN, 467 MARGIN, 468 rect.getWidth() - MARGIN, 469 rect.getHeight() / 2 - MARGIN); 470 } 471 } 472 else { 473 dataRect = new Rectangle( 474 MARGIN, 475 MARGIN, 476 rect.getWidth() - MARGIN, 477 rect.getHeight() * (1 - TOP_SECTION) - MARGIN); 478 } 479 480 if (render == SignatureRenderNameAndDescription) { 481 String signedBy = PdfPKCS7.getSubjectFields((X509Certificate )certChain[0]).getField("CN"); 482 Rectangle sr2 = new Rectangle(signatureRect.getWidth() - MARGIN, signatureRect.getHeight() - MARGIN ); 483 float signedSize = fitText(font, signedBy, sr2, -1, runDirection); 484 485 ColumnText ct2 = new ColumnText(t); 486 ct2.setRunDirection(runDirection); 487 ct2.setSimpleColumn(new Phrase(signedBy, font), signatureRect.getLeft(), signatureRect.getBottom(), signatureRect.getRight(), signatureRect.getTop(), signedSize, Element.ALIGN_LEFT); 488 489 ct2.go(); 490 } 491 else if (render == SignatureRenderGraphicAndDescription) { 492 ColumnText ct2 = new ColumnText(t); 493 ct2.setRunDirection(runDirection); 494 ct2.setSimpleColumn(signatureRect.getLeft(), signatureRect.getBottom(), signatureRect.getRight(), signatureRect.getTop(), 0, Element.ALIGN_RIGHT); 495 496 Image im = Image.getInstance(signatureGraphic); 497 im.scaleToFit(signatureRect.getWidth(), signatureRect.getHeight()); 498 499 Paragraph p = new Paragraph(); 500 float x = 0; 502 float y = -im.getScaledHeight() + 15; 505 506 x = x + (signatureRect.getWidth() - im.getScaledWidth()) / 2; 507 y = y - (signatureRect.getHeight() - im.getScaledHeight()) / 2; 508 p.add(new Chunk(im, x + (signatureRect.getWidth() - im.getScaledWidth()) / 2, y, false)); 509 ct2.addElement(p); 510 ct2.go(); 511 } 512 513 if (size <= 0) { 514 Rectangle sr = new Rectangle(dataRect.getWidth(), dataRect.getHeight()); 515 size = fitText(font, text, sr, 12, runDirection); 516 } 517 ColumnText ct = new ColumnText(t); 518 ct.setRunDirection(runDirection); 519 ct.setSimpleColumn(new Phrase(text, font), dataRect.getLeft(), dataRect.getBottom(), dataRect.getRight(), dataRect.getTop(), size, Element.ALIGN_LEFT); 520 ct.go(); 521 } 522 if (app[3] == null && !acro6Layers) { 523 PdfTemplate t = app[3] = new PdfTemplate(writer); 524 t.setBoundingBox(new Rectangle(100, 100)); 525 writer.addDirectTemplateSimple(t, new PdfName("n3")); 526 t.setLiteral("% DSBlank\n"); 527 } 528 if (app[4] == null && !acro6Layers) { 529 PdfTemplate t = app[4] = new PdfTemplate(writer); 530 t.setBoundingBox(new Rectangle(0, rect.getHeight() * (1 - TOP_SECTION), rect.getRight(), rect.getTop())); 531 writer.addDirectTemplateSimple(t, new PdfName("n4")); 532 Font font; 533 if (layer2Font == null) 534 font = new Font(); 535 else 536 font = new Font(layer2Font); 537 float size = font.getSize(); 538 String text = "Signature Not Verified"; 539 if (layer4Text != null) 540 text = layer4Text; 541 Rectangle sr = new Rectangle(rect.getWidth() - 2 * MARGIN, rect.getHeight() * TOP_SECTION - 2 * MARGIN); 542 size = fitText(font, text, sr, 15, runDirection); 543 ColumnText ct = new ColumnText(t); 544 ct.setRunDirection(runDirection); 545 ct.setSimpleColumn(new Phrase(text, font), MARGIN, 0, rect.getWidth() - MARGIN, rect.getHeight() - MARGIN, size, Element.ALIGN_LEFT); 546 ct.go(); 547 } 548 int rotation = writer.reader.getPageRotation(page); 549 Rectangle rotated = new Rectangle(rect); 550 int n = rotation; 551 while (n > 0) { 552 rotated = rotated.rotate(); 553 n -= 90; 554 } 555 if (frm == null) { 556 frm = new PdfTemplate(writer); 557 frm.setBoundingBox(rotated); 558 writer.addDirectTemplateSimple(frm, new PdfName("FRM")); 559 float scale = Math.min(rect.getWidth(), rect.getHeight()) * 0.9f; 560 float x = (rect.getWidth() - scale) / 2; 561 float y = (rect.getHeight() - scale) / 2; 562 scale /= 100; 563 if (rotation == 90) 564 frm.concatCTM(0, 1, -1, 0, rect.getHeight(), 0); 565 else if (rotation == 180) 566 frm.concatCTM(-1, 0, 0, -1, rect.getWidth(), rect.getHeight()); 567 else if (rotation == 270) 568 frm.concatCTM(0, -1, 1, 0, 0, rect.getWidth()); 569 frm.addTemplate(app[0], 0, 0); 570 if (!acro6Layers) 571 frm.addTemplate(app[1], scale, 0, 0, scale, x, y); 572 frm.addTemplate(app[2], 0, 0); 573 if (!acro6Layers) { 574 frm.addTemplate(app[3], scale, 0, 0, scale, x, y); 575 frm.addTemplate(app[4], 0, 0); 576 } 577 } 578 PdfTemplate napp = new PdfTemplate(writer); 579 napp.setBoundingBox(rotated); 580 writer.addDirectTemplateSimple(napp, null); 581 napp.addTemplate(frm, 0, 0); 582 return napp; 583 } 584 585 594 public static float fitText(Font font, String text, Rectangle rect, float maxFontSize, int runDirection) { 595 try { 596 ColumnText ct = null; 597 int status = 0; 598 if (maxFontSize <= 0) { 599 int cr = 0; 600 int lf = 0; 601 char t[] = text.toCharArray(); 602 for (int k = 0; k < t.length; ++k) { 603 if (t[k] == '\n') 604 ++lf; 605 else if (t[k] == '\r') 606 ++cr; 607 } 608 int minLines = Math.max(cr, lf) + 1; 609 maxFontSize = Math.abs(rect.getHeight()) / minLines - 0.001f; 610 } 611 font.setSize(maxFontSize); 612 Phrase ph = new Phrase(text, font); 613 ct = new ColumnText(null); 614 ct.setSimpleColumn(ph, rect.getLeft(), rect.getBottom(), rect.getRight(), rect.getTop(), maxFontSize, Element.ALIGN_LEFT); 615 ct.setRunDirection(runDirection); 616 status = ct.go(true); 617 if ((status & ColumnText.NO_MORE_TEXT) != 0) 618 return maxFontSize; 619 float precision = 0.1f; 620 float min = 0; 621 float max = maxFontSize; 622 float size = maxFontSize; 623 for (int k = 0; k < 50; ++k) { size = (min + max) / 2; 625 ct = new ColumnText(null); 626 font.setSize(size); 627 ct.setSimpleColumn(new Phrase(text, font), rect.getLeft(), rect.getBottom(), rect.getRight(), rect.getTop(), size, Element.ALIGN_LEFT); 628 ct.setRunDirection(runDirection); 629 status = ct.go(true); 630 if ((status & ColumnText.NO_MORE_TEXT) != 0) { 631 if (max - min < size * precision) 632 return size; 633 min = size; 634 } 635 else 636 max = size; 637 } 638 return size; 639 } 640 catch (Exception e) { 641 throw new ExceptionConverter(e); 642 } 643 } 644 645 653 public void setExternalDigest(byte digest[], byte RSAdata[], String digestEncryptionAlgorithm) { 654 externalDigest = digest; 655 externalRSAdata = RSAdata; 656 this.digestEncryptionAlgorithm = digestEncryptionAlgorithm; 657 } 658 659 663 public String getReason() { 664 return this.reason; 665 } 666 667 671 public void setReason(String reason) { 672 this.reason = reason; 673 } 674 675 679 public String getLocation() { 680 return this.location; 681 } 682 683 687 public void setLocation(String location) { 688 this.location = location; 689 } 690 691 696 public String getProvider() { 697 return this.provider; 698 } 699 700 706 public void setProvider(String provider) { 707 this.provider = provider; 708 } 709 710 714 public java.security.PrivateKey getPrivKey() { 715 return privKey; 716 } 717 718 722 public java.security.cert.Certificate [] getCertChain() { 723 return this.certChain; 724 } 725 726 730 public java.security.cert.CRL [] getCrlList() { 731 return this.crlList; 732 } 733 734 738 public com.lowagie.text.pdf.PdfName getFilter() { 739 return filter; 740 } 741 742 747 public boolean isNewField() { 748 return this.newField; 749 } 750 751 755 public int getPage() { 756 return page; 757 } 758 759 763 public java.lang.String getFieldName() { 764 return fieldName; 765 } 766 767 771 public com.lowagie.text.Rectangle getPageRect() { 772 return pageRect; 773 } 774 775 779 public java.util.Calendar getSignDate() { 780 return signDate; 781 } 782 783 787 public void setSignDate(java.util.Calendar signDate) { 788 this.signDate = signDate; 789 } 790 791 com.lowagie.text.pdf.ByteBuffer getSigout() { 792 return sigout; 793 } 794 795 void setSigout(com.lowagie.text.pdf.ByteBuffer sigout) { 796 this.sigout = sigout; 797 } 798 799 java.io.OutputStream getOriginalout() { 800 return originalout; 801 } 802 803 void setOriginalout(java.io.OutputStream originalout) { 804 this.originalout = originalout; 805 } 806 807 811 public java.io.File getTempFile() { 812 return tempFile; 813 } 814 815 void setTempFile(java.io.File tempFile) { 816 this.tempFile = tempFile; 817 } 818 819 823 public String getNewSigName() { 824 AcroFields af = writer.getAcroFields(); 825 String name = "Signature"; 826 int step = 0; 827 boolean found = false; 828 while (!found) { 829 ++step; 830 String n1 = name + step; 831 if (af.getFieldItem(n1) != null) 832 continue; 833 n1 += "."; 834 found = true; 835 for (Iterator it = af.getFields().keySet().iterator(); it.hasNext();) { 836 String fn = (String )it.next(); 837 if (fn.startsWith(n1)) { 838 found = false; 839 break; 840 } 841 } 842 } 843 name += step; 844 return name; 845 } 846 847 857 public void preClose() throws IOException , DocumentException { 858 preClose(null); 859 } 860 876 public void preClose(HashMap exclusionSizes) throws IOException , DocumentException { 877 if (preClosed) 878 throw new DocumentException("Document already pre closed."); 879 preClosed = true; 880 AcroFields af = writer.getAcroFields(); 881 String name = getFieldName(); 882 boolean fieldExists = !(isInvisible() || isNewField()); 883 int flags = PdfAnnotation.FLAGS_PRINT | PdfAnnotation.FLAGS_LOCKED; 884 PdfIndirectReference refSig = writer.getPdfIndirectReference(); 885 writer.setSigFlags(3); 886 if (fieldExists) { 887 ArrayList widgets = af.getFieldItem(name).widgets; 888 PdfDictionary widget = (PdfDictionary)widgets.get(0); 889 writer.markUsed(widget); 890 widget.put(PdfName.P, writer.getPageReference(getPage())); 891 widget.put(PdfName.V, refSig); 892 PdfObject obj = PdfReader.getPdfObjectRelease(widget.get(PdfName.F)); 893 if (obj != null && obj.isNumber()) 894 flags = ((PdfNumber)obj).intValue() | PdfAnnotation.FLAGS_LOCKED; 895 widget.put(PdfName.F, new PdfNumber(flags)); 896 PdfDictionary ap = new PdfDictionary(); 897 ap.put(PdfName.N, getAppearance().getIndirectReference()); 898 widget.put(PdfName.AP, ap); 899 } 900 else { 901 PdfFormField sigField = PdfFormField.createSignature(writer); 902 sigField.setFieldName(name); 903 sigField.put(PdfName.V, refSig); 904 sigField.setFlags(flags); 905 906 int pagen = getPage(); 907 if (!isInvisible()) 908 sigField.setWidget(getPageRect(), null); 909 else 910 sigField.setWidget(new Rectangle(0, 0), null); 911 sigField.setAppearance(PdfAnnotation.APPEARANCE_NORMAL, getAppearance()); 912 sigField.setPage(pagen); 913 writer.addAnnotation(sigField, pagen); 914 } 915 916 exclusionLocations = new HashMap (); 917 if (cryptoDictionary == null) { 918 if (PdfName.ADOBE_PPKLITE.equals(getFilter())) 919 sigStandard = new PdfSigGenericPKCS.PPKLite(getProvider()); 920 else if (PdfName.ADOBE_PPKMS.equals(getFilter())) 921 sigStandard = new PdfSigGenericPKCS.PPKMS(getProvider()); 922 else if (PdfName.VERISIGN_PPKVS.equals(getFilter())) 923 sigStandard = new PdfSigGenericPKCS.VeriSign(getProvider()); 924 else 925 throw new IllegalArgumentException ("Unknown filter: " + getFilter()); 926 sigStandard.setExternalDigest(externalDigest, externalRSAdata, digestEncryptionAlgorithm); 927 if (getReason() != null) 928 sigStandard.setReason(getReason()); 929 if (getLocation() != null) 930 sigStandard.setLocation(getLocation()); 931 if (getContact() != null) 932 sigStandard.setContact(getContact()); 933 sigStandard.put(PdfName.M, new PdfDate(getSignDate())); 934 sigStandard.setSignInfo(getPrivKey(), getCertChain(), getCrlList()); 935 PdfString contents = (PdfString)sigStandard.get(PdfName.CONTENTS); 936 PdfLiteral lit = new PdfLiteral((contents.toString().length() + (PdfName.ADOBE_PPKLITE.equals(getFilter())?0:64)) * 2 + 2); 937 exclusionLocations.put(PdfName.CONTENTS, lit); 938 sigStandard.put(PdfName.CONTENTS, lit); 939 lit = new PdfLiteral(80); 940 exclusionLocations.put(PdfName.BYTERANGE, lit); 941 sigStandard.put(PdfName.BYTERANGE, lit); 942 if (certificationLevel > 0) { 943 addDocMDP(sigStandard); 944 } 945 if (signatureEvent != null) 946 signatureEvent.getSignatureDictionary(sigStandard); 947 writer.addToBody(sigStandard, refSig, false); 948 } 949 else { 950 PdfLiteral lit = new PdfLiteral(80); 951 exclusionLocations.put(PdfName.BYTERANGE, lit); 952 cryptoDictionary.put(PdfName.BYTERANGE, lit); 953 for (Iterator it = exclusionSizes.entrySet().iterator(); it.hasNext();) { 954 Map.Entry entry = (Map.Entry )it.next(); 955 PdfName key = (PdfName)entry.getKey(); 956 Integer v = (Integer )entry.getValue(); 957 lit = new PdfLiteral(v.intValue()); 958 exclusionLocations.put(key, lit); 959 cryptoDictionary.put(key, lit); 960 } 961 if (certificationLevel > 0) 962 addDocMDP(cryptoDictionary); 963 if (signatureEvent != null) 964 signatureEvent.getSignatureDictionary(cryptoDictionary); 965 writer.addToBody(cryptoDictionary, refSig, false); 966 } 967 if (certificationLevel > 0) { 968 PdfDictionary docmdp = new PdfDictionary(); 970 docmdp.put(new PdfName("DocMDP"), refSig); 971 writer.reader.getCatalog().put(new PdfName("Perms"), docmdp); 972 } 973 writer.close(stamper.getMoreInfo()); 974 975 range = new int[exclusionLocations.size() * 2]; 976 int byteRangePosition = ((PdfLiteral)exclusionLocations.get(PdfName.BYTERANGE)).getPosition(); 977 exclusionLocations.remove(PdfName.BYTERANGE); 978 int idx = 1; 979 for (Iterator it = exclusionLocations.values().iterator(); it.hasNext();) { 980 PdfLiteral lit = (PdfLiteral)it.next(); 981 int n = lit.getPosition(); 982 range[idx++] = n; 983 range[idx++] = lit.getPosLength() + n; 984 } 985 Arrays.sort(range, 1, range.length - 1); 986 for (int k = 3; k < range.length - 2; k += 2) 987 range[k] -= range[k - 1]; 988 989 if (tempFile == null) { 990 bout = sigout.getBuffer(); 991 boutLen = sigout.size(); 992 range[range.length - 1] = boutLen - range[range.length - 2]; 993 ByteBuffer bf = new ByteBuffer(); 994 bf.append('['); 995 for (int k = 0; k < range.length; ++k) 996 bf.append(range[k]).append(' '); 997 bf.append(']'); 998 System.arraycopy(bf.getBuffer(), 0, bout, byteRangePosition, bf.size()); 999 } 1000 else { 1001 try { 1002 raf = new RandomAccessFile (tempFile, "rw"); 1003 int boutLen = (int)raf.length(); 1004 range[range.length - 1] = boutLen - range[range.length - 2]; 1005 ByteBuffer bf = new ByteBuffer(); 1006 bf.append('['); 1007 for (int k = 0; k < range.length; ++k) 1008 bf.append(range[k]).append(' '); 1009 bf.append(']'); 1010 raf.seek(byteRangePosition); 1011 raf.write(bf.getBuffer(), 0, bf.size()); 1012 } 1013 catch (IOException e) { 1014 try{raf.close();}catch(Exception ee){} 1015 try{tempFile.delete();}catch(Exception ee){} 1016 throw e; 1017 } 1018 } 1019 } 1020 1021 1032 public void close(PdfDictionary update) throws IOException , DocumentException { 1033 try { 1034 if (!preClosed) 1035 throw new DocumentException("preClose() must be called first."); 1036 ByteBuffer bf = new ByteBuffer(); 1037 for (Iterator it = update.getKeys().iterator(); it.hasNext();) { 1038 PdfName key = (PdfName)it.next(); 1039 PdfObject obj = update.get(key); 1040 PdfLiteral lit = (PdfLiteral)exclusionLocations.get(key); 1041 if (lit == null) 1042 throw new IllegalArgumentException ("The key " + key.toString() + " didn't reserve space in preClose()."); 1043 bf.reset(); 1044 obj.toPdf(null, bf); 1045 if (bf.size() > lit.getPosLength()) 1046 throw new IllegalArgumentException ("The key " + key.toString() + " is too big. Is " + bf.size() + ", reserved " + lit.getPosLength()); 1047 if (tempFile == null) 1048 System.arraycopy(bf.getBuffer(), 0, bout, lit.getPosition(), bf.size()); 1049 else { 1050 raf.seek(lit.getPosition()); 1051 raf.write(bf.getBuffer(), 0, bf.size()); 1052 } 1053 } 1054 if (update.size() != exclusionLocations.size()) 1055 throw new IllegalArgumentException ("The update dictionary has less keys than required."); 1056 if (tempFile == null) { 1057 originalout.write(bout, 0, boutLen); 1058 } 1059 else { 1060 if (originalout != null) { 1061 raf.seek(0); 1062 int length = (int)raf.length(); 1063 byte buf[] = new byte[8192]; 1064 while (length > 0) { 1065 int r = raf.read(buf, 0, Math.min(buf.length, length)); 1066 if (r < 0) 1067 throw new EOFException ("Unexpected EOF"); 1068 originalout.write(buf, 0, r); 1069 length -= r; 1070 } 1071 } 1072 } 1073 } 1074 finally { 1075 if (tempFile != null) { 1076 try{raf.close();}catch(Exception ee){} 1077 if (originalout != null) 1078 try{tempFile.delete();}catch(Exception ee){} 1079 } 1080 if (originalout != null) 1081 try{originalout.close();}catch(Exception e){} 1082 } 1083 } 1084 1085 private void addDocMDP(PdfDictionary crypto) { 1086 PdfDictionary reference = new PdfDictionary(); 1087 PdfDictionary transformParams = new PdfDictionary(); 1088 transformParams.put(PdfName.P, new PdfNumber(certificationLevel)); 1089 transformParams.put(PdfName.V, new PdfName("1.2")); 1090 transformParams.put(PdfName.TYPE, PdfName.TRANSFORMPARAMS); 1091 reference.put(PdfName.TRANSFORMMETHOD, PdfName.DOCMDP); 1092 reference.put(PdfName.TYPE, PdfName.SIGREF); 1093 reference.put(PdfName.TRANSFORMPARAMS, transformParams); 1094 reference.put(new PdfName("DigestValue"), new PdfString("aa")); 1095 PdfArray loc = new PdfArray(); 1096 loc.add(new PdfNumber(0)); 1097 loc.add(new PdfNumber(0)); 1098 reference.put(new PdfName("DigestLocation"), loc); 1099 reference.put(new PdfName("DigestMethod"), new PdfName("MD5")); 1100 reference.put(PdfName.DATA, writer.reader.getTrailer().get(PdfName.ROOT)); 1101 PdfArray types = new PdfArray(); 1102 types.add(reference); 1103 crypto.put(PdfName.REFERENCE, types); 1104 } 1105 1106 1112 public InputStream getRangeStream() { 1113 return new PdfSignatureAppearance.RangeStream(raf, bout, range); 1114 } 1115 1116 1120 public com.lowagie.text.pdf.PdfDictionary getCryptoDictionary() { 1121 return cryptoDictionary; 1122 } 1123 1124 1128 public void setCryptoDictionary(com.lowagie.text.pdf.PdfDictionary cryptoDictionary) { 1129 this.cryptoDictionary = cryptoDictionary; 1130 } 1131 1132 1136 public com.lowagie.text.pdf.PdfStamper getStamper() { 1137 return stamper; 1138 } 1139 1140 void setStamper(com.lowagie.text.pdf.PdfStamper stamper) { 1141 this.stamper = stamper; 1142 } 1143 1144 1149 public boolean isPreClosed() { 1150 return preClosed; 1151 } 1152 1153 1160 public com.lowagie.text.pdf.PdfSigGenericPKCS getSigStandard() { 1161 return sigStandard; 1162 } 1163 1164 1168 public String getContact() { 1169 return this.contact; 1170 } 1171 1172 1176 public void setContact(String contact) { 1177 this.contact = contact; 1178 } 1179 1180 1184 public Font getLayer2Font() { 1185 return this.layer2Font; 1186 } 1187 1188 1192 public void setLayer2Font(Font layer2Font) { 1193 this.layer2Font = layer2Font; 1194 } 1195 1196 1200 public boolean isAcro6Layers() { 1201 return this.acro6Layers; 1202 } 1203 1204 1208 public void setAcro6Layers(boolean acro6Layers) { 1209 this.acro6Layers = acro6Layers; 1210 } 1211 1212 1215 public void setRunDirection(int runDirection) { 1216 if (runDirection < PdfWriter.RUN_DIRECTION_DEFAULT || runDirection > PdfWriter.RUN_DIRECTION_RTL) 1217 throw new RuntimeException ("Invalid run direction: " + runDirection); 1218 this.runDirection = runDirection; 1219 } 1220 1221 1224 public int getRunDirection() { 1225 return runDirection; 1226 } 1227 1228 1232 public SignatureEvent getSignatureEvent() { 1233 return this.signatureEvent; 1234 } 1235 1236 1240 public void setSignatureEvent(SignatureEvent signatureEvent) { 1241 this.signatureEvent = signatureEvent; 1242 } 1243 1244 1248 public Image getImage() { 1249 return this.image; 1250 } 1251 1252 1256 public void setImage(Image image) { 1257 this.image = image; 1258 } 1259 1260 1264 public float getImageScale() { 1265 return this.imageScale; 1266 } 1267 1268 1275 public void setImageScale(float imageScale) { 1276 this.imageScale = imageScale; 1277 } 1278 1279 1282 public static final String questionMark = 1283 "% DSUnknown\n" + 1284 "q\n" + 1285 "1 G\n" + 1286 "1 g\n" + 1287 "0.1 0 0 0.1 9 0 cm\n" + 1288 "0 J 0 j 4 M []0 d\n" + 1289 "1 i \n" + 1290 "0 g\n" + 1291 "313 292 m\n" + 1292 "313 404 325 453 432 529 c\n" + 1293 "478 561 504 597 504 645 c\n" + 1294 "504 736 440 760 391 760 c\n" + 1295 "286 760 271 681 265 626 c\n" + 1296 "265 625 l\n" + 1297 "100 625 l\n" + 1298 "100 828 253 898 381 898 c\n" + 1299 "451 898 679 878 679 650 c\n" + 1300 "679 555 628 499 538 435 c\n" + 1301 "488 399 467 376 467 292 c\n" + 1302 "313 292 l\n" + 1303 "h\n" + 1304 "308 214 170 -164 re\n" + 1305 "f\n" + 1306 "0.44 G\n" + 1307 "1.2 w\n" + 1308 "1 1 0.4 rg\n" + 1309 "287 318 m\n" + 1310 "287 430 299 479 406 555 c\n" + 1311 "451 587 478 623 478 671 c\n" + 1312 "478 762 414 786 365 786 c\n" + 1313 "260 786 245 707 239 652 c\n" + 1314 "239 651 l\n" + 1315 "74 651 l\n" + 1316 "74 854 227 924 355 924 c\n" + 1317 "425 924 653 904 653 676 c\n" + 1318 "653 581 602 525 512 461 c\n" + 1319 "462 425 441 402 441 318 c\n" + 1320 "287 318 l\n" + 1321 "h\n" + 1322 "282 240 170 -164 re\n" + 1323 "B\n" + 1324 "Q\n"; 1325 1326 1329 private String contact; 1330 1331 1334 private Font layer2Font; 1335 1336 1339 private String layer4Text; 1340 1341 1344 private boolean acro6Layers; 1345 1346 1349 private int runDirection = PdfWriter.RUN_DIRECTION_NO_BIDI; 1350 1351 1354 private SignatureEvent signatureEvent; 1355 1356 1359 private Image image; 1360 1361 1364 private float imageScale; 1365 1366 1369 private static class RangeStream extends InputStream { 1370 private byte b[] = new byte[1]; 1371 private RandomAccessFile raf; 1372 private byte bout[]; 1373 private int range[]; 1374 private int rangePosition = 0; 1375 1376 private RangeStream(RandomAccessFile raf, byte bout[], int range[]) { 1377 this.raf = raf; 1378 this.bout = bout; 1379 this.range = range; 1380 } 1381 1382 1385 public int read() throws IOException { 1386 int n = read(b); 1387 if (n != 1) 1388 return -1; 1389 return b[0] & 0xff; 1390 } 1391 1392 1395 public int read(byte[] b, int off, int len) throws IOException { 1396 if (b == null) { 1397 throw new NullPointerException (); 1398 } else if ((off < 0) || (off > b.length) || (len < 0) || 1399 ((off + len) > b.length) || ((off + len) < 0)) { 1400 throw new IndexOutOfBoundsException (); 1401 } else if (len == 0) { 1402 return 0; 1403 } 1404 if (rangePosition >= range[range.length - 2] + range[range.length - 1]) { 1405 return -1; 1406 } 1407 for (int k = 0; k < range.length; k += 2) { 1408 int start = range[k]; 1409 int end = start + range[k + 1]; 1410 if (rangePosition < start) 1411 rangePosition = start; 1412 if (rangePosition >= start && rangePosition < end) { 1413 int lenf = Math.min(len, end - rangePosition); 1414 if (raf == null) 1415 System.arraycopy(bout, rangePosition, b, off, lenf); 1416 else { 1417 raf.seek(rangePosition); 1418 raf.readFully(b, off, lenf); 1419 } 1420 rangePosition += lenf; 1421 return lenf; 1422 } 1423 } 1424 return -1; 1425 } 1426 } 1427 1428 1431 public interface SignatureEvent { 1432 1436 public void getSignatureDictionary(PdfDictionary sig); 1437 } 1438 1439 private int certificationLevel = NOT_CERTIFIED; 1440 1441 1445 public int getCertificationLevel() { 1446 return this.certificationLevel; 1447 } 1448 1449 1454 public void setCertificationLevel(int certificationLevel) { 1455 this.certificationLevel = certificationLevel; 1456 } 1457} | Popular Tags |