Commit 966429e718c8a0cd458c8efe5aa463cd0052aad0
1 parent
6ec22f11
Update CLI and manual for new encryption granularity (fixes #214)
Showing
6 changed files
with
120 additions
and
9 deletions
ChangeLog
| @@ -16,6 +16,11 @@ | @@ -16,6 +16,11 @@ | ||
| 16 | 16 | ||
| 17 | 2019-01-14 Jay Berkenbilt <ejb@ql.org> | 17 | 2019-01-14 Jay Berkenbilt <ejb@ql.org> |
| 18 | 18 | ||
| 19 | + * Add new CLI flags to 128-bit and 256-bit encryption: --assemble, | ||
| 20 | + --annotate, --form, and --modify-other to control encryption | ||
| 21 | + permissions with more granularity than was allowed with the | ||
| 22 | + --modify flag. Fixes #214. | ||
| 23 | + | ||
| 19 | * Add new versions of | 24 | * Add new versions of |
| 20 | QPDFWriter::setR{3,4,5,6}EncryptionParameters that allow | 25 | QPDFWriter::setR{3,4,5,6}EncryptionParameters that allow |
| 21 | individual setting of the various permission bits. The old | 26 | individual setting of the various permission bits. The old |
manual/qpdf-manual.xml
| @@ -786,7 +786,12 @@ make | @@ -786,7 +786,12 @@ make | ||
| 786 | <listitem> | 786 | <listitem> |
| 787 | <para> | 787 | <para> |
| 788 | Determines whether or not to allow accessibility to visually | 788 | Determines whether or not to allow accessibility to visually |
| 789 | - impaired. | 789 | + impaired. The qpdf library disregards this field when AES is |
| 790 | + used or when 256-bit encryption is used. You should really | ||
| 791 | + never disable accessibility, but qpdf lets you do it in case | ||
| 792 | + you need to configure a file this way for testing purposes. | ||
| 793 | + The PDF spec says that conforming readers should disregard | ||
| 794 | + this permission and always allow accessibility. | ||
| 790 | </para> | 795 | </para> |
| 791 | </listitem> | 796 | </listitem> |
| 792 | </varlistentry> | 797 | </varlistentry> |
| @@ -799,6 +804,45 @@ make | @@ -799,6 +804,45 @@ make | ||
| 799 | </listitem> | 804 | </listitem> |
| 800 | </varlistentry> | 805 | </varlistentry> |
| 801 | <varlistentry> | 806 | <varlistentry> |
| 807 | + <term><option>--assemble=[yn]</option></term> | ||
| 808 | + <listitem> | ||
| 809 | + <para> | ||
| 810 | + Determines whether document assembly (rotation and reordering | ||
| 811 | + of pages) is allowed. | ||
| 812 | + </para> | ||
| 813 | + </listitem> | ||
| 814 | + </varlistentry> | ||
| 815 | + <varlistentry> | ||
| 816 | + <term><option>--annotate=[yn]</option></term> | ||
| 817 | + <listitem> | ||
| 818 | + <para> | ||
| 819 | + Determines whether modifying annotations is allowed. This | ||
| 820 | + includes adding comments and filling in form fields. Also | ||
| 821 | + allows editing of form fields if | ||
| 822 | + <option>--modify-other=y</option> is given. | ||
| 823 | + </para> | ||
| 824 | + </listitem> | ||
| 825 | + </varlistentry> | ||
| 826 | + <varlistentry> | ||
| 827 | + <term><option>--form=[yn]</option></term> | ||
| 828 | + <listitem> | ||
| 829 | + <para> | ||
| 830 | + Determines whether filling form fields is allowed. | ||
| 831 | + </para> | ||
| 832 | + </listitem> | ||
| 833 | + </varlistentry> | ||
| 834 | + <varlistentry> | ||
| 835 | + <term><option>--modify-other=[yn]</option></term> | ||
| 836 | + <listitem> | ||
| 837 | + <para> | ||
| 838 | + Allow all document editing except those controlled separately | ||
| 839 | + by the <option>--assemble</option>, | ||
| 840 | + <option>--annotate</option>, and <option>--form</option> | ||
| 841 | + options. | ||
| 842 | + </para> | ||
| 843 | + </listitem> | ||
| 844 | + </varlistentry> | ||
| 845 | + <varlistentry> | ||
| 802 | <term><option>--print=<replaceable>print-opt</replaceable></option></term> | 846 | <term><option>--print=<replaceable>print-opt</replaceable></option></term> |
| 803 | <listitem> | 847 | <listitem> |
| 804 | <para> | 848 | <para> |
| @@ -829,10 +873,10 @@ make | @@ -829,10 +873,10 @@ make | ||
| 829 | <term><option>--modify=<replaceable>modify-opt</replaceable></option></term> | 873 | <term><option>--modify=<replaceable>modify-opt</replaceable></option></term> |
| 830 | <listitem> | 874 | <listitem> |
| 831 | <para> | 875 | <para> |
| 832 | - Controls modify access. | 876 | + Controls modify access. This way of controlling modify access |
| 877 | + has less granularity than new options added in qpdf 8.4. | ||
| 833 | <option><replaceable>modify-opt</replaceable></option> may be | 878 | <option><replaceable>modify-opt</replaceable></option> may be |
| 834 | - one of the following, each of which implies all the options | ||
| 835 | - that follow it: | 879 | + one of the following: |
| 836 | <itemizedlist> | 880 | <itemizedlist> |
| 837 | <listitem> | 881 | <listitem> |
| 838 | <para> | 882 | <para> |
| @@ -841,12 +885,14 @@ make | @@ -841,12 +885,14 @@ make | ||
| 841 | </listitem> | 885 | </listitem> |
| 842 | <listitem> | 886 | <listitem> |
| 843 | <para> | 887 | <para> |
| 844 | - <option>annotate</option>: allow comment authoring and form operations | 888 | + <option>annotate</option>: allow comment authoring, form |
| 889 | + operations, and document assembly | ||
| 845 | </para> | 890 | </para> |
| 846 | </listitem> | 891 | </listitem> |
| 847 | <listitem> | 892 | <listitem> |
| 848 | <para> | 893 | <para> |
| 849 | <option>form</option>: allow form field fill-in and signing | 894 | <option>form</option>: allow form field fill-in and signing |
| 895 | + and document assembly | ||
| 850 | </para> | 896 | </para> |
| 851 | </listitem> | 897 | </listitem> |
| 852 | <listitem> | 898 | <listitem> |
| @@ -860,6 +906,12 @@ make | @@ -860,6 +906,12 @@ make | ||
| 860 | </para> | 906 | </para> |
| 861 | </listitem> | 907 | </listitem> |
| 862 | </itemizedlist> | 908 | </itemizedlist> |
| 909 | + Using the <option>--modify</option> option does not allow you | ||
| 910 | + to create certain combinations of permissions such as allowing | ||
| 911 | + form filling but not allowing document assembly. Starting with | ||
| 912 | + qpdf 8.4, you can either just use the other options to control | ||
| 913 | + fields individually, or you can use something like | ||
| 914 | + <option>--modify=form --assembly=n</option> to fine tune. | ||
| 863 | </para> | 915 | </para> |
| 864 | </listitem> | 916 | </listitem> |
| 865 | </varlistentry> | 917 | </varlistentry> |
qpdf/qpdf.cc
| @@ -631,6 +631,10 @@ class ArgParser | @@ -631,6 +631,10 @@ class ArgParser | ||
| 631 | void arg128Print(char* parameter); | 631 | void arg128Print(char* parameter); |
| 632 | void arg128Modify(char* parameter); | 632 | void arg128Modify(char* parameter); |
| 633 | void arg128ClearTextMetadata(); | 633 | void arg128ClearTextMetadata(); |
| 634 | + void arg128Assemble(char* parameter); | ||
| 635 | + void arg128Annotate(char* parameter); | ||
| 636 | + void arg128Form(char* parameter); | ||
| 637 | + void arg128ModOther(char* parameter); | ||
| 634 | void arg128UseAes(char* parameter); | 638 | void arg128UseAes(char* parameter); |
| 635 | void arg128ForceV4(); | 639 | void arg128ForceV4(); |
| 636 | void arg256ForceR5(); | 640 | void arg256ForceR5(); |
| @@ -857,11 +861,16 @@ ArgParser::initOptionTable() | @@ -857,11 +861,16 @@ ArgParser::initOptionTable() | ||
| 857 | char const* print128_choices[] = {"full", "low", "none", 0}; | 861 | char const* print128_choices[] = {"full", "low", "none", 0}; |
| 858 | (*t)["print"] = oe_requiredChoices( | 862 | (*t)["print"] = oe_requiredChoices( |
| 859 | &ArgParser::arg128Print, print128_choices); | 863 | &ArgParser::arg128Print, print128_choices); |
| 864 | + (*t)["assemble"] = oe_requiredChoices(&ArgParser::arg128Assemble, yn); | ||
| 865 | + (*t)["annotate"] = oe_requiredChoices(&ArgParser::arg128Annotate, yn); | ||
| 866 | + (*t)["form"] = oe_requiredChoices(&ArgParser::arg128Form, yn); | ||
| 867 | + (*t)["modify-other"] = oe_requiredChoices(&ArgParser::arg128ModOther, yn); | ||
| 860 | char const* modify128_choices[] = | 868 | char const* modify128_choices[] = |
| 861 | {"all", "annotate", "form", "assembly", "none", 0}; | 869 | {"all", "annotate", "form", "assembly", "none", 0}; |
| 862 | (*t)["modify"] = oe_requiredChoices( | 870 | (*t)["modify"] = oe_requiredChoices( |
| 863 | &ArgParser::arg128Modify, modify128_choices); | 871 | &ArgParser::arg128Modify, modify128_choices); |
| 864 | (*t)["cleartext-metadata"] = oe_bare(&ArgParser::arg128ClearTextMetadata); | 872 | (*t)["cleartext-metadata"] = oe_bare(&ArgParser::arg128ClearTextMetadata); |
| 873 | + | ||
| 865 | // The above 128-bit options are also 256-bit options, so copy | 874 | // The above 128-bit options are also 256-bit options, so copy |
| 866 | // what we have so far. Then continue separately with 128 and 256. | 875 | // what we have so far. Then continue separately with 128 and 256. |
| 867 | this->encrypt256_option_table = this->encrypt128_option_table; | 876 | this->encrypt256_option_table = this->encrypt128_option_table; |
| @@ -1048,7 +1057,11 @@ ArgParser::argHelp() | @@ -1048,7 +1057,11 @@ ArgParser::argHelp() | ||
| 1048 | << " --accessibility=[yn] allow accessibility to visually impaired\n" | 1057 | << " --accessibility=[yn] allow accessibility to visually impaired\n" |
| 1049 | << " --extract=[yn] allow other text/graphic extraction\n" | 1058 | << " --extract=[yn] allow other text/graphic extraction\n" |
| 1050 | << " --print=print-opt control printing access\n" | 1059 | << " --print=print-opt control printing access\n" |
| 1051 | - << " --modify=modify-opt control modify access\n" | 1060 | + << " --assemble=[yn] allow document assembly\n" |
| 1061 | + << " --annotate=[yn] allow commenting/filling form fields\n" | ||
| 1062 | + << " --form=[yn] allow filling form fields\n" | ||
| 1063 | + << " --modify-other=[yn] allow other modifications\n" | ||
| 1064 | + << " --modify=modify-opt control modify access (old way)\n" | ||
| 1052 | << " --cleartext-metadata prevents encryption of metadata\n" | 1065 | << " --cleartext-metadata prevents encryption of metadata\n" |
| 1053 | << " --use-aes=[yn] indicates whether to use AES encryption\n" | 1066 | << " --use-aes=[yn] indicates whether to use AES encryption\n" |
| 1054 | << " --force-V4 forces use of V=4 encryption handler\n" | 1067 | << " --force-V4 forces use of V=4 encryption handler\n" |
| @@ -1072,7 +1085,8 @@ ArgParser::argHelp() | @@ -1072,7 +1085,8 @@ ArgParser::argHelp() | ||
| 1072 | << " assembly allow document assembly only\n" | 1085 | << " assembly allow document assembly only\n" |
| 1073 | << " none allow no modifications\n" | 1086 | << " none allow no modifications\n" |
| 1074 | << "\n" | 1087 | << "\n" |
| 1075 | - << "The default for each permission option is to be fully permissive.\n" | 1088 | + << "The default for each permission option is to be fully permissive. Please\n" |
| 1089 | + << "refer to the manual for more details on the modify options.\n" | ||
| 1076 | << "\n" | 1090 | << "\n" |
| 1077 | << "Specifying cleartext-metadata forces the PDF version to at least 1.5.\n" | 1091 | << "Specifying cleartext-metadata forces the PDF version to at least 1.5.\n" |
| 1078 | << "Specifying use of AES forces the PDF version to at least 1.6. These\n" | 1092 | << "Specifying use of AES forces the PDF version to at least 1.6. These\n" |
| @@ -1915,6 +1929,30 @@ ArgParser::arg128ClearTextMetadata() | @@ -1915,6 +1929,30 @@ ArgParser::arg128ClearTextMetadata() | ||
| 1915 | } | 1929 | } |
| 1916 | 1930 | ||
| 1917 | void | 1931 | void |
| 1932 | +ArgParser::arg128Assemble(char* parameter) | ||
| 1933 | +{ | ||
| 1934 | + o.r3_assemble = (strcmp(parameter, "y") == 0); | ||
| 1935 | +} | ||
| 1936 | + | ||
| 1937 | +void | ||
| 1938 | +ArgParser::arg128Annotate(char* parameter) | ||
| 1939 | +{ | ||
| 1940 | + o.r3_annotate_and_form = (strcmp(parameter, "y") == 0); | ||
| 1941 | +} | ||
| 1942 | + | ||
| 1943 | +void | ||
| 1944 | +ArgParser::arg128Form(char* parameter) | ||
| 1945 | +{ | ||
| 1946 | + o.r3_form_filling = (strcmp(parameter, "y") == 0); | ||
| 1947 | +} | ||
| 1948 | + | ||
| 1949 | +void | ||
| 1950 | +ArgParser::arg128ModOther(char* parameter) | ||
| 1951 | +{ | ||
| 1952 | + o.r3_modify_other = (strcmp(parameter, "y") == 0); | ||
| 1953 | +} | ||
| 1954 | + | ||
| 1955 | +void | ||
| 1918 | ArgParser::arg128UseAes(char* parameter) | 1956 | ArgParser::arg128UseAes(char* parameter) |
| 1919 | { | 1957 | { |
| 1920 | o.use_aes = (strcmp(parameter, "y") == 0); | 1958 | o.use_aes = (strcmp(parameter, "y") == 0); |
qpdf/qtest/qpdf.test
| @@ -2687,6 +2687,24 @@ my @encrypted_files = | @@ -2687,6 +2687,24 @@ my @encrypted_files = | ||
| 2687 | ['R3,V2,U=view,O=master', 'master', | 2687 | ['R3,V2,U=view,O=master', 'master', |
| 2688 | '-accessibility=n -print=low', -2564, | 2688 | '-accessibility=n -print=low', -2564, |
| 2689 | 0, 1, 1, 0, 1, 1, 1, 1, 1], | 2689 | 0, 1, 1, 0, 1, 1, 1, 1, 1], |
| 2690 | + ['R3,V2,U=view,O=master', 'master', | ||
| 2691 | + '-modify=all -assemble=n', -1028, | ||
| 2692 | + 1, 1, 1, 1, 0, 1, 1, 1, 0], | ||
| 2693 | + ['R3,V2,U=view,O=master', 'master', | ||
| 2694 | + '-modify=none -form=y', -1068, | ||
| 2695 | + 1, 1, 1, 1, 0, 1, 0, 0, 0], | ||
| 2696 | + ['R3,V2,U=view,O=master', 'master', | ||
| 2697 | + '-modify=annotate -assemble=n', -1036, | ||
| 2698 | + 1, 1, 1, 1, 0, 1, 1, 0, 0], | ||
| 2699 | + ['R3,V2,U=view,O=master', 'master', | ||
| 2700 | + '-form=n', -260, | ||
| 2701 | + 1, 1, 1, 1, 1, 0, 1, 1, 0], | ||
| 2702 | + ['R3,V2,U=view,O=master', 'master', | ||
| 2703 | + '-annotate=n', -36, | ||
| 2704 | + 1, 1, 1, 1, 1, 1, 0, 1, 0], | ||
| 2705 | + ['R3,V2,U=view,O=master', 'master', | ||
| 2706 | + '-modify-other=n', -12, | ||
| 2707 | + 1, 1, 1, 1, 1, 1, 1, 0, 0], | ||
| 2690 | ['R2,V1', '', | 2708 | ['R2,V1', '', |
| 2691 | '-print=n -modify=n -extract=n -annotate=n', -64, | 2709 | '-print=n -modify=n -extract=n -annotate=n', -64, |
| 2692 | 0, 0, 0, 0, 0, 0, 0, 0, 0], | 2710 | 0, 0, 0, 0, 0, 0, 0, 0, 0], |
qpdf/qtest/qpdf/completion-encrypt-128.out