1 | #include "mupdf/fitz.h" |
2 | #include "mupdf/pdf.h" |
3 | |
4 | #include "mupdf/helpers/pkcs7-check.h" |
5 | |
6 | char *pdf_signature_error_description(enum pdf_signature_error err) |
7 | { |
8 | switch (err) |
9 | { |
10 | case PDF_SIGNATURE_ERROR_OKAY: |
11 | return "" ; |
12 | case PDF_SIGNATURE_ERROR_NO_SIGNATURES: |
13 | return "No signatures." ; |
14 | case PDF_SIGNATURE_ERROR_NO_CERTIFICATE: |
15 | return "No certificate." ; |
16 | case PDF_SIGNATURE_ERROR_DIGEST_FAILURE: |
17 | return "Signature invalidated by change to document." ; |
18 | case PDF_SIGNATURE_ERROR_SELF_SIGNED: |
19 | return "Self-signed certificate." ; |
20 | case PDF_SIGNATURE_ERROR_SELF_SIGNED_IN_CHAIN: |
21 | return "Self-signed certificate in chain." ; |
22 | case PDF_SIGNATURE_ERROR_NOT_TRUSTED: |
23 | return "Certificate not trusted." ; |
24 | default: |
25 | case PDF_SIGNATURE_ERROR_UNKNOWN: |
26 | return "Unknown error." ; |
27 | } |
28 | } |
29 | |
30 | #ifdef HAVE_LIBCRYPTO |
31 | #include "mupdf/helpers/pkcs7-openssl.h" |
32 | #include <string.h> |
33 | |
34 | static void pdf_format_designated_name(pdf_pkcs7_designated_name *name, char *buf, int buflen) |
35 | { |
36 | int i, n; |
37 | const char *part[] = { |
38 | "CN=" , name->cn, |
39 | ", O=" , name->o, |
40 | ", OU=" , name->ou, |
41 | ", emailAddress=" , name->email, |
42 | ", C=" , name->c}; |
43 | |
44 | if (buflen) |
45 | buf[0] = 0; |
46 | |
47 | n = sizeof(part)/sizeof(*part); |
48 | for (i = 0; i < n; i++) |
49 | if (part[i]) |
50 | fz_strlcat(buf, part[i], buflen); |
51 | } |
52 | |
53 | void pdf_signature_designated_name(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char *buf, int buflen) |
54 | { |
55 | char *contents = NULL; |
56 | int contents_len = pdf_signature_contents(ctx, doc, signature, &contents); |
57 | pdf_pkcs7_designated_name *name = NULL; |
58 | fz_try(ctx) |
59 | { |
60 | name = pkcs7_openssl_designated_name(ctx, contents, contents_len); |
61 | if (name) |
62 | { |
63 | pdf_format_designated_name(name, buf, buflen); |
64 | pkcs7_openssl_drop_designated_name(ctx, name); |
65 | } |
66 | else if (buflen > 0) |
67 | buf[0] = '\0'; |
68 | } |
69 | fz_always(ctx) |
70 | fz_free(ctx, contents); |
71 | fz_catch(ctx) |
72 | fz_rethrow(ctx); |
73 | } |
74 | |
75 | enum pdf_signature_error pdf_check_digest(fz_context *ctx, pdf_document *doc, pdf_obj *signature) |
76 | { |
77 | enum pdf_signature_error err; |
78 | fz_stream *bytes = NULL; |
79 | char *contents = NULL; |
80 | int contents_len = pdf_signature_contents(ctx, doc, signature, &contents); |
81 | fz_var(err); |
82 | fz_var(bytes); |
83 | fz_try(ctx) |
84 | { |
85 | bytes = pdf_signature_hash_bytes(ctx, doc, signature); |
86 | err = pkcs7_openssl_check_digest(ctx, bytes, contents, contents_len); |
87 | } |
88 | fz_always(ctx) |
89 | { |
90 | fz_drop_stream(ctx, bytes); |
91 | fz_free(ctx, contents); |
92 | } |
93 | fz_catch(ctx) |
94 | { |
95 | fz_rethrow(ctx); |
96 | } |
97 | |
98 | return err; |
99 | } |
100 | |
101 | enum pdf_signature_error pdf_check_certificate(fz_context *ctx, pdf_document *doc, pdf_obj *signature) |
102 | { |
103 | char *contents = NULL; |
104 | int contents_len = pdf_signature_contents(ctx, doc, signature, &contents); |
105 | enum pdf_signature_error result; |
106 | fz_try(ctx) |
107 | result = pkcs7_openssl_check_certificate(contents, contents_len); |
108 | fz_always(ctx) |
109 | fz_free(ctx, contents); |
110 | fz_catch(ctx) |
111 | fz_rethrow(ctx); |
112 | return result; |
113 | } |
114 | |
115 | int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char *ebuf, int ebufsize) |
116 | { |
117 | int res = 0; |
118 | |
119 | if (pdf_xref_obj_is_unsaved_signature(doc, signature)) |
120 | { |
121 | fz_strlcpy(ebuf, "Signed but document yet to be saved." , ebufsize); |
122 | if (ebufsize > 0) |
123 | ebuf[ebufsize-1] = 0; |
124 | return 0; |
125 | } |
126 | |
127 | fz_var(res); |
128 | fz_try(ctx) |
129 | { |
130 | if (pdf_signature_is_signed(ctx, doc, signature)) |
131 | { |
132 | enum pdf_signature_error err; |
133 | |
134 | err = pdf_check_digest(ctx, doc, signature); |
135 | if (err == PDF_SIGNATURE_ERROR_OKAY) |
136 | err = pdf_check_certificate(ctx, doc, signature); |
137 | |
138 | fz_strlcpy(ebuf, pdf_signature_error_description(err), ebufsize); |
139 | res = (err == PDF_SIGNATURE_ERROR_OKAY); |
140 | |
141 | switch (err) |
142 | { |
143 | case PDF_SIGNATURE_ERROR_SELF_SIGNED: |
144 | case PDF_SIGNATURE_ERROR_SELF_SIGNED_IN_CHAIN: |
145 | case PDF_SIGNATURE_ERROR_NOT_TRUSTED: |
146 | { |
147 | int len; |
148 | fz_strlcat(ebuf, " (" , ebufsize); |
149 | len = strlen(ebuf); |
150 | pdf_signature_designated_name(ctx, doc, signature, ebuf + len, ebufsize - len); |
151 | fz_strlcat(ebuf, ")" , ebufsize); |
152 | } |
153 | break; |
154 | default: |
155 | break; |
156 | } |
157 | } |
158 | else |
159 | { |
160 | res = 0; |
161 | fz_strlcpy(ebuf, "Not signed." , ebufsize); |
162 | } |
163 | } |
164 | fz_catch(ctx) |
165 | { |
166 | res = 0; |
167 | fz_strlcpy(ebuf, fz_caught_message(ctx), ebufsize); |
168 | } |
169 | |
170 | if (ebufsize > 0) |
171 | ebuf[ebufsize-1] = 0; |
172 | |
173 | return res; |
174 | } |
175 | |
176 | #else |
177 | |
178 | void pdf_signature_designated_name(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char *buf, int buflen) |
179 | { |
180 | fz_throw(ctx, FZ_ERROR_GENERIC, "No OpenSSL support." ); |
181 | } |
182 | |
183 | enum pdf_signature_error pdf_check_digest(fz_context *ctx, pdf_document *doc, pdf_obj *signature) |
184 | { |
185 | fz_throw(ctx, FZ_ERROR_GENERIC, "No OpenSSL support." ); |
186 | return 0; |
187 | } |
188 | |
189 | enum pdf_signature_error pdf_check_certificate(fz_context *ctx, pdf_document *doc, pdf_obj *signature) |
190 | { |
191 | fz_throw(ctx, FZ_ERROR_GENERIC, "No OpenSSL support." ); |
192 | return 0; |
193 | } |
194 | |
195 | |
196 | int pdf_check_signature(fz_context *ctx, pdf_document *doc, pdf_obj *signature, char *ebuf, int ebufsize) |
197 | { |
198 | fz_strlcpy(ebuf, "No digital signing support in this build" , ebufsize); |
199 | return 0; |
200 | } |
201 | |
202 | #endif |
203 | |