1 | /* $Id: RTSignTool.cpp 106264 2024-10-09 20:50:12Z vboxsync $ */
|
---|
2 | /** @file
|
---|
3 | * IPRT - Signing Tool.
|
---|
4 | */
|
---|
5 |
|
---|
6 | /*
|
---|
7 | * Copyright (C) 2006-2024 Oracle and/or its affiliates.
|
---|
8 | *
|
---|
9 | * This file is part of VirtualBox base platform packages, as
|
---|
10 | * available from https://www.virtualbox.org.
|
---|
11 | *
|
---|
12 | * This program is free software; you can redistribute it and/or
|
---|
13 | * modify it under the terms of the GNU General Public License
|
---|
14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
15 | * License.
|
---|
16 | *
|
---|
17 | * This program is distributed in the hope that it will be useful, but
|
---|
18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
20 | * General Public License for more details.
|
---|
21 | *
|
---|
22 | * You should have received a copy of the GNU General Public License
|
---|
23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
24 | *
|
---|
25 | * The contents of this file may alternatively be used under the terms
|
---|
26 | * of the Common Development and Distribution License Version 1.0
|
---|
27 | * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
|
---|
28 | * in the VirtualBox distribution, in which case the provisions of the
|
---|
29 | * CDDL are applicable instead of those of the GPL.
|
---|
30 | *
|
---|
31 | * You may elect to license modified versions of this file under the
|
---|
32 | * terms and conditions of either the GPL or the CDDL or both.
|
---|
33 | *
|
---|
34 | * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
|
---|
35 | */
|
---|
36 |
|
---|
37 |
|
---|
38 | /*********************************************************************************************************************************
|
---|
39 | * Header Files *
|
---|
40 | *********************************************************************************************************************************/
|
---|
41 | #include <iprt/assert.h>
|
---|
42 | #include <iprt/buildconfig.h>
|
---|
43 | #include <iprt/ctype.h>
|
---|
44 | #include <iprt/err.h>
|
---|
45 | #include <iprt/getopt.h>
|
---|
46 | #include <iprt/file.h>
|
---|
47 | #include <iprt/initterm.h>
|
---|
48 | #include <iprt/ldr.h>
|
---|
49 | #include <iprt/message.h>
|
---|
50 | #include <iprt/mem.h>
|
---|
51 | #include <iprt/path.h>
|
---|
52 | #include <iprt/stream.h>
|
---|
53 | #include <iprt/string.h>
|
---|
54 | #ifdef RT_OS_WINDOWS
|
---|
55 | # include <iprt/utf16.h>
|
---|
56 | #endif
|
---|
57 | #include <iprt/uuid.h>
|
---|
58 | #include <iprt/zero.h>
|
---|
59 | #include <iprt/formats/asn1.h>
|
---|
60 | #include <iprt/formats/mach-o.h>
|
---|
61 | #ifndef RT_OS_WINDOWS
|
---|
62 | # include <iprt/formats/pecoff.h>
|
---|
63 | #else
|
---|
64 | # define WIN_CERTIFICATE_ALIGNMENT UINT32_C(8) /* from pecoff.h */
|
---|
65 | #endif
|
---|
66 | #include <iprt/crypto/applecodesign.h>
|
---|
67 | #include <iprt/crypto/digest.h>
|
---|
68 | #include <iprt/crypto/key.h>
|
---|
69 | #include <iprt/crypto/x509.h>
|
---|
70 | #include <iprt/crypto/pkcs7.h>
|
---|
71 | #include <iprt/crypto/store.h>
|
---|
72 | #include <iprt/crypto/spc.h>
|
---|
73 | #include <iprt/crypto/tsp.h>
|
---|
74 | #include <iprt/cpp/ministring.h>
|
---|
75 | #ifdef VBOX
|
---|
76 | # include <VBox/sup.h> /* Certificates */
|
---|
77 | #endif
|
---|
78 | #ifdef RT_OS_WINDOWS
|
---|
79 | # include <iprt/win/windows.h>
|
---|
80 | # include <iprt/win/imagehlp.h>
|
---|
81 | # include <wincrypt.h>
|
---|
82 | # include <ncrypt.h>
|
---|
83 | #endif
|
---|
84 | #include "internal/ldr.h" /* for IMAGE_XX_SIGNATURE defines */
|
---|
85 |
|
---|
86 |
|
---|
87 | /*********************************************************************************************************************************
|
---|
88 | * Defined Constants And Macros *
|
---|
89 | *********************************************************************************************************************************/
|
---|
90 | #define OPT_OFF_CERT_FILE 0 /**< signtool /f file */
|
---|
91 | #define OPT_OFF_CERT_SHA1 1 /**< signtool /sha1 thumbprint */
|
---|
92 | #define OPT_OFF_CERT_SUBJECT 2 /**< signtool /n name */
|
---|
93 | #define OPT_OFF_CERT_STORE 3 /**< signtool /s store */
|
---|
94 | #define OPT_OFF_CERT_STORE_MACHINE 4 /**< signtool /sm */
|
---|
95 | #define OPT_OFF_KEY_FILE 5 /**< no signtool equivalent, other than maybe /f. */
|
---|
96 | #define OPT_OFF_KEY_PASSWORD 6 /**< signtool /p pass */
|
---|
97 | #define OPT_OFF_KEY_PASSWORD_FILE 7 /**< no signtool equivalent. */
|
---|
98 | #define OPT_OFF_KEY_NAME 8 /**< signtool /kc name */
|
---|
99 | #define OPT_OFF_KEY_PROVIDER 9 /**< signtool /csp name (CSP = cryptographic service provider) */
|
---|
100 |
|
---|
101 | #define OPT_CERT_KEY_SWITCH_CASES(a_Instance, a_uBase, a_chOpt, a_ValueUnion, a_rcExit) \
|
---|
102 | case (a_uBase) + OPT_OFF_CERT_FILE: \
|
---|
103 | case (a_uBase) + OPT_OFF_CERT_SHA1: \
|
---|
104 | case (a_uBase) + OPT_OFF_CERT_SUBJECT: \
|
---|
105 | case (a_uBase) + OPT_OFF_CERT_STORE: \
|
---|
106 | case (a_uBase) + OPT_OFF_CERT_STORE_MACHINE: \
|
---|
107 | case (a_uBase) + OPT_OFF_KEY_FILE: \
|
---|
108 | case (a_uBase) + OPT_OFF_KEY_PASSWORD: \
|
---|
109 | case (a_uBase) + OPT_OFF_KEY_PASSWORD_FILE: \
|
---|
110 | case (a_uBase) + OPT_OFF_KEY_NAME: \
|
---|
111 | case (a_uBase) + OPT_OFF_KEY_PROVIDER: \
|
---|
112 | a_rcExit = a_Instance.handleOption((a_chOpt) - (a_uBase), &(a_ValueUnion)); \
|
---|
113 | break
|
---|
114 |
|
---|
115 | #define OPT_CERT_KEY_GETOPTDEF_ENTRIES(a_szPrefix, a_szSuffix, a_uBase) \
|
---|
116 | { a_szPrefix "cert-file" a_szSuffix, (a_uBase) + OPT_OFF_CERT_FILE, RTGETOPT_REQ_STRING }, \
|
---|
117 | { a_szPrefix "cert-sha1" a_szSuffix, (a_uBase) + OPT_OFF_CERT_SHA1, RTGETOPT_REQ_STRING }, \
|
---|
118 | { a_szPrefix "cert-subject" a_szSuffix, (a_uBase) + OPT_OFF_CERT_SUBJECT, RTGETOPT_REQ_STRING }, \
|
---|
119 | { a_szPrefix "cert-store" a_szSuffix, (a_uBase) + OPT_OFF_CERT_STORE, RTGETOPT_REQ_STRING }, \
|
---|
120 | { a_szPrefix "cert-machine-store" a_szSuffix, (a_uBase) + OPT_OFF_CERT_STORE_MACHINE, RTGETOPT_REQ_NOTHING }, \
|
---|
121 | { a_szPrefix "key-file" a_szSuffix, (a_uBase) + OPT_OFF_KEY_FILE, RTGETOPT_REQ_STRING }, \
|
---|
122 | { a_szPrefix "key-password" a_szSuffix, (a_uBase) + OPT_OFF_KEY_PASSWORD, RTGETOPT_REQ_STRING }, \
|
---|
123 | { a_szPrefix "key-password-file" a_szSuffix, (a_uBase) + OPT_OFF_KEY_PASSWORD_FILE, RTGETOPT_REQ_STRING }, \
|
---|
124 | { a_szPrefix "key-name" a_szSuffix, (a_uBase) + OPT_OFF_KEY_NAME, RTGETOPT_REQ_STRING }, \
|
---|
125 | { a_szPrefix "key-provider" a_szSuffix, (a_uBase) + OPT_OFF_KEY_PROVIDER, RTGETOPT_REQ_STRING }
|
---|
126 |
|
---|
127 | #define OPT_CERT_KEY_GETOPTDEF_COMPAT_ENTRIES(a_uBase) \
|
---|
128 | { "/f", (a_uBase) + OPT_OFF_CERT_FILE, RTGETOPT_REQ_STRING }, \
|
---|
129 | { "/sha1", (a_uBase) + OPT_OFF_CERT_SHA1, RTGETOPT_REQ_STRING }, \
|
---|
130 | { "/n", (a_uBase) + OPT_OFF_CERT_SUBJECT, RTGETOPT_REQ_STRING }, \
|
---|
131 | { "/s", (a_uBase) + OPT_OFF_CERT_STORE, RTGETOPT_REQ_STRING }, \
|
---|
132 | { "/sm", (a_uBase) + OPT_OFF_CERT_STORE_MACHINE, RTGETOPT_REQ_NOTHING }, \
|
---|
133 | { "/p", (a_uBase) + OPT_OFF_KEY_PASSWORD, RTGETOPT_REQ_STRING }, \
|
---|
134 | { "/kc", (a_uBase) + OPT_OFF_KEY_NAME, RTGETOPT_REQ_STRING }, \
|
---|
135 | { "/csp", (a_uBase) + OPT_OFF_KEY_PROVIDER, RTGETOPT_REQ_STRING }
|
---|
136 |
|
---|
137 | #define OPT_CERT_KEY_SYNOPSIS(a_szPrefix, a_szSuffix) \
|
---|
138 | "[" a_szPrefix "cert-file" a_szSuffix " <file.pem|file.crt>] " \
|
---|
139 | "[" a_szPrefix "cert-sha1" a_szSuffix " <fingerprint>] " \
|
---|
140 | "[" a_szPrefix "cert-subject" a_szSuffix " <part-name>] " \
|
---|
141 | "[" a_szPrefix "cert-store" a_szSuffix " <store>] " \
|
---|
142 | "[" a_szPrefix "cert-machine-store" a_szSuffix "] " \
|
---|
143 | "[" a_szPrefix "key-file" a_szSuffix " <file.pem|file.p12>] " \
|
---|
144 | "[" a_szPrefix "key-password" a_szSuffix " <password>] " \
|
---|
145 | "[" a_szPrefix "key-password-file" a_szSuffix " <file>|stdin] " \
|
---|
146 | "[" a_szPrefix "key-name" a_szSuffix " <name>] " \
|
---|
147 | "[" a_szPrefix "key-provider" a_szSuffix " <csp>] "
|
---|
148 |
|
---|
149 | #define OPT_HASH_PAGES 1200
|
---|
150 | #define OPT_NO_HASH_PAGES 1201
|
---|
151 | #define OPT_ADD_CERT 1202
|
---|
152 | #define OPT_TIMESTAMP_TYPE 1203
|
---|
153 | #define OPT_TIMESTAMP_TYPE_2 1204
|
---|
154 | #define OPT_TIMESTAMP_OVERRIDE 1205
|
---|
155 | #define OPT_NO_SIGNING_TIME 1206
|
---|
156 | #define OPT_FILE_TYPE 1207
|
---|
157 | #define OPT_IGNORED 1208
|
---|
158 |
|
---|
159 |
|
---|
160 | /*********************************************************************************************************************************
|
---|
161 | * Structures and Typedefs *
|
---|
162 | *********************************************************************************************************************************/
|
---|
163 | /** Help detail levels. */
|
---|
164 | typedef enum RTSIGNTOOLHELP
|
---|
165 | {
|
---|
166 | RTSIGNTOOLHELP_USAGE,
|
---|
167 | RTSIGNTOOLHELP_FULL
|
---|
168 | } RTSIGNTOOLHELP;
|
---|
169 |
|
---|
170 |
|
---|
171 | /** Filetypes. */
|
---|
172 | typedef enum RTSIGNTOOLFILETYPE
|
---|
173 | {
|
---|
174 | RTSIGNTOOLFILETYPE_INVALID = 0,
|
---|
175 | RTSIGNTOOLFILETYPE_DETECT,
|
---|
176 | RTSIGNTOOLFILETYPE_EXE,
|
---|
177 | RTSIGNTOOLFILETYPE_CAT,
|
---|
178 | RTSIGNTOOLFILETYPE_UNKNOWN,
|
---|
179 | RTSIGNTOOLFILETYPE_END
|
---|
180 | } RTSIGNTOOLFILETYPE;
|
---|
181 |
|
---|
182 |
|
---|
183 | /**
|
---|
184 | * PKCS\#7 signature data.
|
---|
185 | */
|
---|
186 | typedef struct SIGNTOOLPKCS7
|
---|
187 | {
|
---|
188 | /** The file type. */
|
---|
189 | RTSIGNTOOLFILETYPE enmType;
|
---|
190 | /** The raw signature. */
|
---|
191 | uint8_t *pbBuf;
|
---|
192 | /** Size of the raw signature. */
|
---|
193 | size_t cbBuf;
|
---|
194 | /** The filename. */
|
---|
195 | const char *pszFilename;
|
---|
196 | /** The outer content info wrapper. */
|
---|
197 | RTCRPKCS7CONTENTINFO ContentInfo;
|
---|
198 | /** Pointer to the decoded SignedData inside the ContentInfo member. */
|
---|
199 | PRTCRPKCS7SIGNEDDATA pSignedData;
|
---|
200 |
|
---|
201 | /** Newly encoded raw signature.
|
---|
202 | * @sa SignToolPkcs7_Encode() */
|
---|
203 | uint8_t *pbNewBuf;
|
---|
204 | /** Size of newly encoded raw signature. */
|
---|
205 | size_t cbNewBuf;
|
---|
206 |
|
---|
207 | } SIGNTOOLPKCS7;
|
---|
208 | typedef SIGNTOOLPKCS7 *PSIGNTOOLPKCS7;
|
---|
209 |
|
---|
210 |
|
---|
211 | /**
|
---|
212 | * PKCS\#7 signature data for executable.
|
---|
213 | */
|
---|
214 | typedef struct SIGNTOOLPKCS7EXE : public SIGNTOOLPKCS7
|
---|
215 | {
|
---|
216 | /** The module handle. */
|
---|
217 | RTLDRMOD hLdrMod;
|
---|
218 | } SIGNTOOLPKCS7EXE;
|
---|
219 | typedef SIGNTOOLPKCS7EXE *PSIGNTOOLPKCS7EXE;
|
---|
220 |
|
---|
221 |
|
---|
222 | /**
|
---|
223 | * Data for the show exe (signature) command.
|
---|
224 | */
|
---|
225 | typedef struct SHOWEXEPKCS7 : public SIGNTOOLPKCS7EXE
|
---|
226 | {
|
---|
227 | /** The verbosity. */
|
---|
228 | unsigned cVerbosity;
|
---|
229 | /** The prefix buffer. */
|
---|
230 | char szPrefix[256];
|
---|
231 | /** Temporary buffer. */
|
---|
232 | char szTmp[4096];
|
---|
233 | } SHOWEXEPKCS7;
|
---|
234 | typedef SHOWEXEPKCS7 *PSHOWEXEPKCS7;
|
---|
235 |
|
---|
236 |
|
---|
237 | /*********************************************************************************************************************************
|
---|
238 | * Internal Functions *
|
---|
239 | *********************************************************************************************************************************/
|
---|
240 | static RTEXITCODE HandleHelp(int cArgs, char **papszArgs);
|
---|
241 | static RTEXITCODE HelpHelp(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel);
|
---|
242 | static RTEXITCODE HandleVersion(int cArgs, char **papszArgs);
|
---|
243 | static int HandleShowExeWorkerPkcs7DisplaySignerInfo(PSHOWEXEPKCS7 pThis, size_t offPrefix, PCRTCRPKCS7SIGNERINFO pSignerInfo);
|
---|
244 | static int HandleShowExeWorkerPkcs7Display(PSHOWEXEPKCS7 pThis, PRTCRPKCS7SIGNEDDATA pSignedData, size_t offPrefix,
|
---|
245 | PCRTCRPKCS7CONTENTINFO pContentInfo);
|
---|
246 |
|
---|
247 |
|
---|
248 | /*********************************************************************************************************************************
|
---|
249 | * Certificate and Private Key Handling (options, ++). *
|
---|
250 | *********************************************************************************************************************************/
|
---|
251 | #ifdef RT_OS_WINDOWS
|
---|
252 |
|
---|
253 | /** @todo create a better fake certificate. */
|
---|
254 | const unsigned char g_abFakeCertificate[] =
|
---|
255 | {
|
---|
256 | 0x30, 0x82, 0x03, 0xb2, 0x30, 0x82, 0x02, 0x9a, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x31, /* 0x00000000: 0...0..........1 */
|
---|
257 | 0xba, 0xd6, 0xbc, 0x5d, 0x9a, 0xe0, 0xb0, 0x4e, 0xd4, 0xfa, 0xcc, 0xfb, 0x47, 0x00, 0x5c, 0x30, /* 0x00000010: ...]...N....G.\0 */
|
---|
258 | 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x71, /* 0x00000020: ...*.H........0q */
|
---|
259 | 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x54, 0x69, 0x6d, 0x65, 0x73, /* 0x00000030: 1.0...U....Times */
|
---|
260 | 0x74, 0x61, 0x6d, 0x70, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x32, 0x31, 0x0c, /* 0x00000040: tamp Signing 21. */
|
---|
261 | 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03, 0x44, 0x65, 0x76, 0x31, 0x15, 0x30, 0x13, /* 0x00000050: 0...U....Dev1.0. */
|
---|
262 | 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, 0x6f, 0x6d, 0x70, /* 0x00000060: ..U....Test Comp */
|
---|
263 | 0x61, 0x6e, 0x79, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, 0x09, 0x53, 0x74, /* 0x00000070: any1.0...U....St */
|
---|
264 | 0x75, 0x74, 0x74, 0x67, 0x61, 0x72, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x08, /* 0x00000080: uttgart1.0...U.. */
|
---|
265 | 0x0c, 0x02, 0x42, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13, 0x02, 0x44, /* 0x00000090: ..BB1.0...U....D */
|
---|
266 | 0x45, 0x30, 0x1e, 0x17, 0x0d, 0x30, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x31, 0x30, /* 0x000000a0: E0...00010100010 */
|
---|
267 | 0x31, 0x5a, 0x17, 0x0d, 0x33, 0x36, 0x31, 0x32, 0x33, 0x31, 0x32, 0x32, 0x35, 0x39, 0x35, 0x39, /* 0x000000b0: 1Z..361231225959 */
|
---|
268 | 0x5a, 0x30, 0x71, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03, 0x0c, 0x13, 0x54, 0x69, /* 0x000000c0: Z0q1.0...U....Ti */
|
---|
269 | 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x20, 0x53, 0x69, 0x67, 0x6e, 0x69, 0x6e, 0x67, 0x20, /* 0x000000d0: mestamp Signing */
|
---|
270 | 0x32, 0x31, 0x0c, 0x30, 0x0a, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x0c, 0x03, 0x44, 0x65, 0x76, 0x31, /* 0x000000e0: 21.0...U....Dev1 */
|
---|
271 | 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x0c, 0x0c, 0x54, 0x65, 0x73, 0x74, 0x20, 0x43, /* 0x000000f0: .0...U....Test C */
|
---|
272 | 0x6f, 0x6d, 0x70, 0x61, 0x6e, 0x79, 0x31, 0x12, 0x30, 0x10, 0x06, 0x03, 0x55, 0x04, 0x07, 0x0c, /* 0x00000100: ompany1.0...U... */
|
---|
273 | 0x09, 0x53, 0x74, 0x75, 0x74, 0x74, 0x67, 0x61, 0x72, 0x74, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, /* 0x00000110: .Stuttgart1.0... */
|
---|
274 | 0x55, 0x04, 0x08, 0x0c, 0x02, 0x42, 0x42, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, /* 0x00000120: U....BB1.0...U.. */
|
---|
275 | 0x13, 0x02, 0x44, 0x45, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, /* 0x00000130: ..DE0.."0...*.H. */
|
---|
276 | 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01, 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, /* 0x00000140: ............0... */
|
---|
277 | 0x02, 0x82, 0x01, 0x01, 0x00, 0xdb, 0x18, 0x63, 0x33, 0xf2, 0x08, 0x90, 0x5a, 0xab, 0xda, 0x88, /* 0x00000150: .......c3...Z... */
|
---|
278 | 0x73, 0x86, 0x49, 0xea, 0x8b, 0xaf, 0xcf, 0x67, 0x15, 0xa5, 0x39, 0xe6, 0xa2, 0x94, 0x0c, 0x3f, /* 0x00000160: s.I....g..9....? */
|
---|
279 | 0xa1, 0x2e, 0x6c, 0xd2, 0xdf, 0x01, 0x65, 0x6d, 0xed, 0x6c, 0x4c, 0xac, 0xe7, 0x77, 0x7a, 0x45, /* 0x00000170: ..l...em.lL..wzE */
|
---|
280 | 0x05, 0x6b, 0x24, 0xf3, 0xaf, 0x45, 0x35, 0x6e, 0x64, 0x0a, 0xac, 0x1d, 0x37, 0xe1, 0x33, 0xa4, /* 0x00000180: .k$..E5nd...7.3. */
|
---|
281 | 0x92, 0xec, 0x45, 0xe8, 0x99, 0xc1, 0xde, 0x6f, 0xab, 0x7c, 0xf0, 0xdc, 0xe2, 0xc5, 0x42, 0xa3, /* 0x00000190: ..E....o.|....B. */
|
---|
282 | 0xea, 0xf5, 0x8a, 0xf9, 0x0e, 0xe7, 0xb3, 0x35, 0xa2, 0x75, 0x5e, 0x87, 0xd2, 0x2a, 0xd1, 0x27, /* 0x000001a0: .......5.u^..*.' */
|
---|
283 | 0xa6, 0x79, 0x9e, 0xfe, 0x90, 0xbf, 0x97, 0xa4, 0xa1, 0xd8, 0xf7, 0xd7, 0x05, 0x59, 0x44, 0x27, /* 0x000001b0: .y...........YD' */
|
---|
284 | 0x39, 0x6e, 0x33, 0x01, 0x2e, 0x46, 0x92, 0x47, 0xbe, 0x50, 0x91, 0x26, 0x27, 0xe5, 0x4b, 0x3a, /* 0x000001c0: 9n3..F.G.P.&'.K: */
|
---|
285 | 0x76, 0x26, 0x64, 0x92, 0x0c, 0xa0, 0x54, 0x43, 0x6f, 0x56, 0xcc, 0x7b, 0xd0, 0xe3, 0xd8, 0x39, /* 0x000001d0: v&d...TCoV.{...9 */
|
---|
286 | 0x5f, 0xb9, 0x41, 0xda, 0x1c, 0x62, 0x88, 0x0c, 0x45, 0x03, 0x63, 0xf8, 0xff, 0xe5, 0x3e, 0x87, /* 0x000001e0: _.A..b..E.c...>. */
|
---|
287 | 0x0c, 0x75, 0xc9, 0xdd, 0xa2, 0xc0, 0x1b, 0x63, 0x19, 0xeb, 0x09, 0x9d, 0xa1, 0xbb, 0x0f, 0x63, /* 0x000001f0: .u.....c.......c */
|
---|
288 | 0x67, 0x1c, 0xa3, 0xfd, 0x2f, 0xd1, 0x2a, 0xda, 0xd8, 0x93, 0x66, 0x45, 0x54, 0xef, 0x8b, 0x6d, /* 0x00000200: g.....*...fET..m */
|
---|
289 | 0x12, 0x15, 0x0f, 0xd4, 0xb5, 0x04, 0x17, 0x30, 0x5b, 0xfa, 0x12, 0x96, 0x48, 0x5b, 0x38, 0x65, /* 0x00000210: .......0[...H[8e */
|
---|
290 | 0xfd, 0x8f, 0x0c, 0xa3, 0x11, 0x46, 0x49, 0xe0, 0x62, 0xc3, 0xcc, 0x34, 0xe6, 0xfb, 0xab, 0x51, /* 0x00000220: .....FI.b..4...Q */
|
---|
291 | 0xc3, 0xd4, 0x0b, 0xdc, 0x39, 0x93, 0x87, 0x90, 0x10, 0x9f, 0xce, 0x43, 0x27, 0x31, 0xd5, 0x4e, /* 0x00000230: ....9......C'1.N */
|
---|
292 | 0x52, 0x60, 0xf1, 0x93, 0xd5, 0x06, 0xc4, 0x4e, 0x65, 0xb6, 0x35, 0x4a, 0x64, 0x15, 0xf8, 0xaf, /* 0x00000240: R`.....Ne.5Jd... */
|
---|
293 | 0x71, 0xb2, 0x42, 0x50, 0x89, 0x02, 0x03, 0x01, 0x00, 0x01, 0xa3, 0x46, 0x30, 0x44, 0x30, 0x0e, /* 0x00000250: q.BP.......F0D0. */
|
---|
294 | 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x07, 0x80, 0x30, 0x13, /* 0x00000260: ..U...........0. */
|
---|
295 | 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04, 0x0c, 0x30, 0x0a, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, /* 0x00000270: ..U.%..0...+.... */
|
---|
296 | 0x07, 0x03, 0x08, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16, 0x04, 0x14, 0x52, 0x9d, /* 0x00000280: ...0...U......R. */
|
---|
297 | 0x4d, 0xcd, 0x41, 0xe1, 0xd2, 0x68, 0x22, 0xd3, 0x10, 0x33, 0x01, 0xca, 0xff, 0x00, 0x1d, 0x27, /* 0x00000290: M.A..h"..3.....' */
|
---|
298 | 0xa4, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, /* 0x000002a0: ..0...*.H....... */
|
---|
299 | 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0xc5, 0x5a, 0x51, 0x83, 0x68, 0x3f, 0x06, 0x39, 0x79, 0x13, /* 0x000002b0: .......ZQ.h?.9y. */
|
---|
300 | 0xa6, 0xf0, 0x1a, 0xf9, 0x29, 0x16, 0x2d, 0xa2, 0x07, 0xaa, 0x9b, 0xc3, 0x13, 0x88, 0x39, 0x69, /* 0x000002c0: ....).-.......9i */
|
---|
301 | 0xba, 0xf7, 0x0d, 0xfb, 0xc0, 0x6e, 0x3a, 0x0b, 0x49, 0x10, 0xd1, 0xbe, 0x36, 0x91, 0x3f, 0x9d, /* 0x000002d0: .....n:.I...6.?. */
|
---|
302 | 0xa1, 0xe8, 0xc4, 0x91, 0xf9, 0x02, 0xe1, 0xf1, 0x01, 0x15, 0x09, 0xb7, 0xa1, 0xf1, 0xec, 0x43, /* 0x000002e0: ...............C */
|
---|
303 | 0x0d, 0x73, 0xd1, 0x31, 0x02, 0x4a, 0xce, 0x21, 0xf2, 0xa7, 0x99, 0x7c, 0xee, 0x85, 0x54, 0xc0, /* 0x000002f0: .s.1.J.!...|..T. */
|
---|
304 | 0x55, 0x9b, 0x19, 0x37, 0xe8, 0xcf, 0x94, 0x41, 0x10, 0x6e, 0x67, 0xdd, 0x86, 0xaf, 0xb7, 0xfe, /* 0x00000300: U..7...A.ng..... */
|
---|
305 | 0x50, 0x05, 0xf6, 0xfb, 0x0a, 0xdf, 0x88, 0xb5, 0x59, 0x69, 0x98, 0x27, 0xf8, 0x81, 0x6a, 0x4a, /* 0x00000310: P.......Yi.'..jJ */
|
---|
306 | 0x7c, 0xf3, 0x63, 0xa9, 0x41, 0x78, 0x76, 0x12, 0xdb, 0x0e, 0x94, 0x0a, 0xdb, 0x1d, 0x3c, 0x87, /* 0x00000320: |.c.Axv.......<. */
|
---|
307 | 0x35, 0xca, 0x28, 0xeb, 0xb0, 0x62, 0x27, 0x69, 0xe2, 0xf3, 0x84, 0x48, 0xa2, 0x2d, 0xd7, 0x0e, /* 0x00000330: 5.(..b'i...H.-.. */
|
---|
308 | 0x4b, 0x6d, 0x39, 0xa7, 0x3e, 0x04, 0x94, 0x8e, 0xb6, 0x4b, 0x91, 0x01, 0x68, 0xf9, 0xd2, 0x75, /* 0x00000340: Km9.>....K..h..u */
|
---|
309 | 0x1b, 0xac, 0x42, 0x3b, 0x85, 0xfc, 0x5b, 0x48, 0x3a, 0x13, 0xe7, 0x1c, 0x17, 0xcd, 0x84, 0x89, /* 0x00000350: ..B;..[H:....... */
|
---|
310 | 0x9e, 0x5f, 0xe3, 0x77, 0xc0, 0xae, 0x34, 0xc3, 0x87, 0x76, 0x4a, 0x23, 0x30, 0xa0, 0xe1, 0x45, /* 0x00000360: ._.w..4..vJ#0..E */
|
---|
311 | 0x94, 0x2a, 0x5b, 0x6b, 0x5a, 0xf0, 0x1a, 0x7e, 0xa6, 0xc4, 0xed, 0xe4, 0xac, 0x5d, 0xdf, 0x87, /* 0x00000370: .*[kZ..~.....].. */
|
---|
312 | 0x8f, 0xc5, 0xb4, 0x8c, 0xbc, 0x70, 0xc1, 0xf7, 0xb2, 0x72, 0xbd, 0x73, 0xc9, 0x4e, 0xed, 0x8d, /* 0x00000380: .....p...r.s.N.. */
|
---|
313 | 0x29, 0x33, 0xe9, 0x14, 0xc1, 0x5e, 0xff, 0x39, 0xa8, 0xe7, 0x9a, 0x3b, 0x7a, 0x3c, 0xce, 0x5d, /* 0x00000390: )3...^.9...;z<.] */
|
---|
314 | 0x0f, 0x3c, 0x82, 0x90, 0xff, 0x81, 0x82, 0x00, 0x82, 0x5f, 0xba, 0x08, 0x79, 0xb1, 0x97, 0xc3, /* 0x000003a0: .<......._..y... */
|
---|
315 | 0x09, 0x75, 0xc0, 0x04, 0x9b, 0x67, /* 0x000003b0: .u...g */
|
---|
316 | };
|
---|
317 |
|
---|
318 | const unsigned char g_abFakeRsaKey[] =
|
---|
319 | {
|
---|
320 | 0x30, 0x82, 0x04, 0xa4, 0x02, 0x01, 0x00, 0x02, 0x82, 0x01, 0x01, 0x00, 0xdb, 0x18, 0x63, 0x33, /* 0x00000000: 0.............c3 */
|
---|
321 | 0xf2, 0x08, 0x90, 0x5a, 0xab, 0xda, 0x88, 0x73, 0x86, 0x49, 0xea, 0x8b, 0xaf, 0xcf, 0x67, 0x15, /* 0x00000010: ...Z...s.I....g. */
|
---|
322 | 0xa5, 0x39, 0xe6, 0xa2, 0x94, 0x0c, 0x3f, 0xa1, 0x2e, 0x6c, 0xd2, 0xdf, 0x01, 0x65, 0x6d, 0xed, /* 0x00000020: .9....?..l...em. */
|
---|
323 | 0x6c, 0x4c, 0xac, 0xe7, 0x77, 0x7a, 0x45, 0x05, 0x6b, 0x24, 0xf3, 0xaf, 0x45, 0x35, 0x6e, 0x64, /* 0x00000030: lL..wzE.k$..E5nd */
|
---|
324 | 0x0a, 0xac, 0x1d, 0x37, 0xe1, 0x33, 0xa4, 0x92, 0xec, 0x45, 0xe8, 0x99, 0xc1, 0xde, 0x6f, 0xab, /* 0x00000040: ...7.3...E....o. */
|
---|
325 | 0x7c, 0xf0, 0xdc, 0xe2, 0xc5, 0x42, 0xa3, 0xea, 0xf5, 0x8a, 0xf9, 0x0e, 0xe7, 0xb3, 0x35, 0xa2, /* 0x00000050: |....B........5. */
|
---|
326 | 0x75, 0x5e, 0x87, 0xd2, 0x2a, 0xd1, 0x27, 0xa6, 0x79, 0x9e, 0xfe, 0x90, 0xbf, 0x97, 0xa4, 0xa1, /* 0x00000060: u^..*.'.y....... */
|
---|
327 | 0xd8, 0xf7, 0xd7, 0x05, 0x59, 0x44, 0x27, 0x39, 0x6e, 0x33, 0x01, 0x2e, 0x46, 0x92, 0x47, 0xbe, /* 0x00000070: ....YD'9n3..F.G. */
|
---|
328 | 0x50, 0x91, 0x26, 0x27, 0xe5, 0x4b, 0x3a, 0x76, 0x26, 0x64, 0x92, 0x0c, 0xa0, 0x54, 0x43, 0x6f, /* 0x00000080: P.&'.K:v&d...TCo */
|
---|
329 | 0x56, 0xcc, 0x7b, 0xd0, 0xe3, 0xd8, 0x39, 0x5f, 0xb9, 0x41, 0xda, 0x1c, 0x62, 0x88, 0x0c, 0x45, /* 0x00000090: V.{...9_.A..b..E */
|
---|
330 | 0x03, 0x63, 0xf8, 0xff, 0xe5, 0x3e, 0x87, 0x0c, 0x75, 0xc9, 0xdd, 0xa2, 0xc0, 0x1b, 0x63, 0x19, /* 0x000000a0: .c...>..u.....c. */
|
---|
331 | 0xeb, 0x09, 0x9d, 0xa1, 0xbb, 0x0f, 0x63, 0x67, 0x1c, 0xa3, 0xfd, 0x2f, 0xd1, 0x2a, 0xda, 0xd8, /* 0x000000b0: ......cg.....*.. */
|
---|
332 | 0x93, 0x66, 0x45, 0x54, 0xef, 0x8b, 0x6d, 0x12, 0x15, 0x0f, 0xd4, 0xb5, 0x04, 0x17, 0x30, 0x5b, /* 0x000000c0: .fET..m.......0[ */
|
---|
333 | 0xfa, 0x12, 0x96, 0x48, 0x5b, 0x38, 0x65, 0xfd, 0x8f, 0x0c, 0xa3, 0x11, 0x46, 0x49, 0xe0, 0x62, /* 0x000000d0: ...H[8e.....FI.b */
|
---|
334 | 0xc3, 0xcc, 0x34, 0xe6, 0xfb, 0xab, 0x51, 0xc3, 0xd4, 0x0b, 0xdc, 0x39, 0x93, 0x87, 0x90, 0x10, /* 0x000000e0: ..4...Q....9.... */
|
---|
335 | 0x9f, 0xce, 0x43, 0x27, 0x31, 0xd5, 0x4e, 0x52, 0x60, 0xf1, 0x93, 0xd5, 0x06, 0xc4, 0x4e, 0x65, /* 0x000000f0: ..C'1.NR`.....Ne */
|
---|
336 | 0xb6, 0x35, 0x4a, 0x64, 0x15, 0xf8, 0xaf, 0x71, 0xb2, 0x42, 0x50, 0x89, 0x02, 0x03, 0x01, 0x00, /* 0x00000100: .5Jd...q.BP..... */
|
---|
337 | 0x01, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd0, 0x5e, 0x09, 0x3a, 0xc5, 0xdc, 0xcf, 0x2c, 0xec, 0x74, /* 0x00000110: .......^.:...,.t */
|
---|
338 | 0x11, 0x81, 0x8d, 0x1d, 0x8f, 0x2a, 0xfa, 0x31, 0x4d, 0xe0, 0x90, 0x1a, 0xd8, 0xf5, 0x95, 0xc7, /* 0x00000120: .....*.1M....... */
|
---|
339 | 0x70, 0x5c, 0x62, 0x42, 0xac, 0xe9, 0xd9, 0xf2, 0x14, 0xf1, 0xd0, 0x25, 0xbb, 0xeb, 0x06, 0xfe, /* 0x00000130: p\bB.......%.... */
|
---|
340 | 0x09, 0xd6, 0x75, 0x67, 0xd7, 0x39, 0xc1, 0xa0, 0x67, 0x34, 0x4d, 0xd2, 0x12, 0x97, 0xaa, 0x5d, /* 0x00000140: ..ug.9..g4M....] */
|
---|
341 | 0xeb, 0x0e, 0xb0, 0x16, 0x6c, 0x78, 0x8e, 0xa0, 0x75, 0xa3, 0xaa, 0x57, 0x88, 0x3b, 0x43, 0x4f, /* 0x00000150: ....lx..u..W.;CO */
|
---|
342 | 0x75, 0x85, 0x67, 0xb0, 0x9b, 0xdd, 0x49, 0x0e, 0x6e, 0xdb, 0xea, 0xb3, 0xd4, 0x88, 0x54, 0xa0, /* 0x00000160: u.g...I.n.....T. */
|
---|
343 | 0x46, 0x0d, 0x55, 0x6d, 0x98, 0xbd, 0x20, 0xf9, 0x9f, 0x61, 0x2d, 0x6f, 0xc7, 0xd7, 0x16, 0x66, /* 0x00000170: F.Um.. ..a-o...f */
|
---|
344 | 0x72, 0xc7, 0x73, 0xbe, 0x9e, 0x48, 0xdc, 0x65, 0x12, 0x46, 0x35, 0x69, 0x55, 0xd8, 0x6b, 0x81, /* 0x00000180: r.s..H.e.F5iU.k. */
|
---|
345 | 0x78, 0x40, 0x15, 0x93, 0x60, 0x31, 0x4e, 0x87, 0x15, 0x2a, 0x74, 0x74, 0x7b, 0xa0, 0x1f, 0x59, /* 0x00000190: x@..`1N..*tt{..Y */
|
---|
346 | 0x8d, 0xc8, 0x3f, 0xdd, 0xf0, 0x13, 0x88, 0x2a, 0x4a, 0xf2, 0xf5, 0xf1, 0x9e, 0xf3, 0x2d, 0x9c, /* 0x000001a0: ..?....*J.....-. */
|
---|
347 | 0x8e, 0xbc, 0xb1, 0x21, 0x45, 0xc7, 0x44, 0x0c, 0x6a, 0xfe, 0x4c, 0x20, 0xdc, 0x73, 0xda, 0x62, /* 0x000001b0: ...!E.D.j.L .s.b */
|
---|
348 | 0x21, 0xcb, 0xdf, 0x06, 0xfc, 0x90, 0xc2, 0xbd, 0xd6, 0xde, 0xfb, 0xf6, 0x08, 0x69, 0x5d, 0xea, /* 0x000001c0: !............i]. */
|
---|
349 | 0xb3, 0x7f, 0x93, 0x61, 0xf2, 0xc1, 0xd0, 0x61, 0x4f, 0xd5, 0x5b, 0x63, 0xba, 0xb0, 0x3b, 0x07, /* 0x000001d0: ...a...aO.[c..;. */
|
---|
350 | 0x7a, 0x55, 0xcd, 0xa1, 0xae, 0x8a, 0x92, 0x21, 0xcc, 0x2f, 0x5b, 0xf8, 0x40, 0x6a, 0xcd, 0xd5, /* 0x000001e0: zU.....!..[.@j.. */
|
---|
351 | 0x5f, 0x15, 0xf4, 0xb6, 0xbd, 0xe5, 0x91, 0xb9, 0xa8, 0xcc, 0x2a, 0xa8, 0xa6, 0x67, 0x57, 0x2b, /* 0x000001f0: _.........*..gW+ */
|
---|
352 | 0x4b, 0xe9, 0x88, 0xe0, 0xbb, 0x58, 0xac, 0x69, 0x5f, 0x3c, 0x76, 0x28, 0xa6, 0x9d, 0xbc, 0x71, /* 0x00000200: K....X.i_<v(...q */
|
---|
353 | 0x7f, 0xcb, 0x0c, 0xc0, 0xbd, 0x61, 0x02, 0x81, 0x81, 0x00, 0xfc, 0x62, 0x79, 0x5b, 0xac, 0xf6, /* 0x00000210: .....a.....by[.. */
|
---|
354 | 0x9b, 0x8c, 0xaa, 0x76, 0x2a, 0x30, 0x0e, 0xcf, 0x6b, 0x88, 0x72, 0x54, 0x8c, 0xdf, 0xf3, 0x9d, /* 0x00000220: ...v*0..k.rT.... */
|
---|
355 | 0x84, 0xbb, 0xe7, 0x9d, 0xd4, 0x04, 0x29, 0x3c, 0xb5, 0x9d, 0x60, 0x9a, 0xcc, 0x12, 0xf3, 0xfa, /* 0x00000230: ......)<..`..... */
|
---|
356 | 0x64, 0x30, 0x23, 0x47, 0xc6, 0xa4, 0x8b, 0x6c, 0x73, 0x6c, 0x6b, 0x78, 0x82, 0xec, 0x05, 0x19, /* 0x00000240: d0#G...lslkx.... */
|
---|
357 | 0xde, 0xdd, 0xde, 0x52, 0xc5, 0x20, 0xd1, 0x11, 0x58, 0x19, 0x07, 0x5a, 0x90, 0xdd, 0x22, 0x91, /* 0x00000250: ...R. ..X..Z..". */
|
---|
358 | 0x89, 0x22, 0x3f, 0x12, 0x54, 0x1a, 0xb8, 0x79, 0xd8, 0x6c, 0xbc, 0xf5, 0x0d, 0xc7, 0x73, 0x5c, /* 0x00000260: ."?.T..y.l....s\ */
|
---|
359 | 0xed, 0xba, 0x40, 0x2b, 0x72, 0x34, 0x34, 0x97, 0xfa, 0x49, 0xf6, 0x43, 0x7c, 0xbc, 0x61, 0x30, /* 0x00000270: ..@+r44..I.C|.a0 */
|
---|
360 | 0x54, 0x22, 0x21, 0x5f, 0x77, 0x68, 0x6b, 0x83, 0x95, 0xc6, 0x8d, 0xb8, 0x25, 0x3a, 0xd3, 0xb2, /* 0x00000280: T"!_whk.....%:.. */
|
---|
361 | 0xbe, 0x29, 0x94, 0x01, 0x15, 0xf0, 0x36, 0x9d, 0x3e, 0xff, 0x02, 0x81, 0x81, 0x00, 0xde, 0x3b, /* 0x00000290: .)....6.>......; */
|
---|
362 | 0xd6, 0x4b, 0x38, 0x69, 0x9b, 0x71, 0x29, 0x89, 0xd4, 0x6d, 0x8c, 0x41, 0xee, 0xe2, 0x4d, 0xfc, /* 0x000002a0: .K8i.q)..m.A..M. */
|
---|
363 | 0xf0, 0x9a, 0x73, 0xf1, 0x15, 0x94, 0xac, 0x1b, 0x68, 0x5f, 0x79, 0x15, 0x3a, 0x41, 0x55, 0x09, /* 0x000002b0: ..s.....h_y.:AU. */
|
---|
364 | 0xc7, 0x1e, 0xec, 0x27, 0x67, 0xe2, 0xdc, 0x54, 0xa8, 0x09, 0xe6, 0x46, 0x92, 0x92, 0x03, 0x8d, /* 0x000002c0: ...'g..T...F.... */
|
---|
365 | 0xe5, 0x96, 0xfb, 0x1a, 0xdd, 0x59, 0x6f, 0x92, 0xf1, 0xf6, 0x8f, 0x76, 0xb0, 0xc5, 0xe6, 0xd7, /* 0x000002d0: .....Yo....v.... */
|
---|
366 | 0x1b, 0x25, 0xaf, 0x04, 0x9f, 0xd8, 0x71, 0x27, 0x97, 0x99, 0x23, 0x09, 0x7d, 0xef, 0x06, 0x13, /* 0x000002e0: .%....q'..#.}... */
|
---|
367 | 0xab, 0xdc, 0xa2, 0xd8, 0x5f, 0xc5, 0xec, 0xf3, 0x62, 0x20, 0x72, 0x7b, 0xa8, 0xc7, 0x09, 0x24, /* 0x000002f0: ...._...b r{...$ */
|
---|
368 | 0xaf, 0x72, 0xc9, 0xea, 0xb8, 0x2d, 0xda, 0x00, 0xc8, 0xfe, 0xb4, 0x9f, 0x9f, 0xc7, 0xa9, 0xf7, /* 0x00000300: .r...-.......... */
|
---|
369 | 0x1d, 0xce, 0xb1, 0xdb, 0xc5, 0x8a, 0x4e, 0xe8, 0x88, 0x77, 0x68, 0xdd, 0xf8, 0x77, 0x02, 0x81, /* 0x00000310: ......N..wh..w.. */
|
---|
370 | 0x80, 0x5b, 0xa5, 0x8e, 0x98, 0x01, 0xa8, 0xd3, 0x37, 0x33, 0x37, 0x11, 0x7e, 0xbe, 0x02, 0x07, /* 0x00000320: .[......737.~... */
|
---|
371 | 0xf4, 0x56, 0x3f, 0xe9, 0x9f, 0xf1, 0x20, 0xc3, 0xf0, 0x4f, 0xdc, 0xf9, 0xfe, 0x40, 0xd3, 0x30, /* 0x00000330: .V?... [email protected] */
|
---|
372 | 0xc7, 0xe3, 0x2a, 0x92, 0xec, 0x56, 0xf8, 0x17, 0xa5, 0x7b, 0x4a, 0x37, 0x11, 0xcd, 0x27, 0x26, /* 0x00000340: ..*..V...{J7..'& */
|
---|
373 | 0x8a, 0xba, 0x43, 0xda, 0x96, 0xc6, 0x0b, 0x6c, 0xe8, 0x78, 0x30, 0xea, 0x30, 0x4e, 0x7a, 0xd3, /* 0x00000350: ..C....l.x0.0Nz. */
|
---|
374 | 0xd8, 0xd2, 0xd8, 0xca, 0x3d, 0xe2, 0xad, 0xa2, 0x74, 0x73, 0x1e, 0xbe, 0xb7, 0xad, 0x41, 0x61, /* 0x00000360: ....=...ts....Aa */
|
---|
375 | 0x9b, 0xaa, 0xc9, 0xf9, 0xa4, 0xf1, 0x79, 0x4f, 0x42, 0x10, 0xc7, 0x36, 0x03, 0x4b, 0x0d, 0xdc, /* 0x00000370: ......yOB..6.K.. */
|
---|
376 | 0xef, 0x3a, 0xa3, 0xab, 0x09, 0xe4, 0xe8, 0xdd, 0xc4, 0x3f, 0x06, 0x21, 0xa0, 0x23, 0x5a, 0x76, /* 0x00000380: .:.......?.!.#Zv */
|
---|
377 | 0xea, 0xd0, 0xcf, 0x8b, 0x85, 0x5f, 0x16, 0x4b, 0x03, 0x62, 0x21, 0x3a, 0xcc, 0x2d, 0xa8, 0xd0, /* 0x00000390: ....._.K.b!:.-.. */
|
---|
378 | 0x15, 0x02, 0x81, 0x80, 0x51, 0xf6, 0x89, 0xbb, 0xa6, 0x6b, 0xb4, 0xcb, 0xd0, 0xc1, 0x27, 0xda, /* 0x000003a0: ....Q....k....'. */
|
---|
379 | 0xdb, 0x6e, 0xf9, 0xd6, 0xf7, 0x62, 0x81, 0xae, 0xc5, 0x72, 0x36, 0x3e, 0x66, 0x17, 0x99, 0xb0, /* 0x000003b0: .n...b...r6>f... */
|
---|
380 | 0x14, 0xad, 0x52, 0x96, 0x03, 0xf2, 0x1e, 0x41, 0x76, 0x61, 0xb6, 0x3c, 0x02, 0x7d, 0x2a, 0x98, /* 0x000003c0: ..R....Ava.<.}*. */
|
---|
381 | 0xb4, 0x18, 0x75, 0x38, 0x6b, 0x1d, 0x2b, 0x7f, 0x3a, 0xcf, 0x96, 0xb1, 0xc4, 0xa7, 0xd2, 0x9b, /* 0x000003d0: ..u8k.+.:....... */
|
---|
382 | 0xd8, 0x1f, 0xb3, 0x64, 0xda, 0x15, 0x9d, 0xca, 0x91, 0x39, 0x48, 0x67, 0x00, 0x9c, 0xd4, 0x99, /* 0x000003e0: ...d.....9Hg.... */
|
---|
383 | 0xc3, 0x45, 0x5d, 0xf0, 0x09, 0x32, 0xba, 0x21, 0x1e, 0xe2, 0x64, 0xb8, 0x50, 0x03, 0x17, 0xbe, /* 0x000003f0: .E]..2.!..d.P... */
|
---|
384 | 0xd5, 0xda, 0x6b, 0xce, 0x34, 0xbe, 0x16, 0x03, 0x65, 0x1b, 0x2f, 0xa0, 0xa1, 0x95, 0xc6, 0x8b, /* 0x00000400: ..k.4...e....... */
|
---|
385 | 0xc2, 0x3c, 0x59, 0x26, 0xbf, 0xb6, 0x07, 0x85, 0x53, 0x2d, 0xb6, 0x36, 0xa3, 0x91, 0xb9, 0xbb, /* 0x00000410: .<Y&....S-.6.... */
|
---|
386 | 0x28, 0xaf, 0x2d, 0x53, 0x02, 0x81, 0x81, 0x00, 0xd7, 0xbc, 0x70, 0xd8, 0x18, 0x4f, 0x65, 0x8c, /* 0x00000420: (.-S......p..Oe. */
|
---|
387 | 0x68, 0xca, 0x35, 0x77, 0x43, 0x50, 0x9b, 0xa1, 0xa3, 0x9a, 0x0e, 0x2d, 0x7b, 0x38, 0xf8, 0xba, /* 0x00000430: h.5wCP.....-{8.. */
|
---|
388 | 0x14, 0x91, 0x3b, 0xc3, 0x3b, 0x1b, 0xa0, 0x6d, 0x45, 0xe4, 0xa8, 0x28, 0x97, 0xf6, 0x89, 0x13, /* 0x00000440: ..;.;..mE..(.... */
|
---|
389 | 0xb6, 0x16, 0x6d, 0x65, 0x47, 0x8c, 0xa6, 0x21, 0xf8, 0x6a, 0xce, 0x4e, 0x44, 0x5e, 0x81, 0x47, /* 0x00000450: ..meG..!.j.ND^.G */
|
---|
390 | 0xd9, 0xad, 0x8a, 0xb9, 0xd9, 0xe9, 0x3e, 0x33, 0x1e, 0x5f, 0xe9, 0xe9, 0xa7, 0xea, 0x60, 0x75, /* 0x00000460: ......>3._....`u */
|
---|
391 | 0x02, 0x57, 0x71, 0xb5, 0xed, 0x47, 0x77, 0xda, 0x1a, 0x40, 0x38, 0xab, 0x82, 0xd2, 0x0d, 0xf5, /* 0x00000470: .Wq..Gw..@8..... */
|
---|
392 | 0x0e, 0x8e, 0xa9, 0x24, 0xdc, 0x30, 0xc9, 0x98, 0xa2, 0x05, 0xcd, 0xca, 0x01, 0xcf, 0xae, 0x1d, /* 0x00000480: ...$.0.......... */
|
---|
393 | 0xe9, 0x02, 0x47, 0x0e, 0x46, 0x1d, 0x52, 0x02, 0x9a, 0x99, 0x22, 0x23, 0x7f, 0xf8, 0x9e, 0xc2, /* 0x00000490: ..G.F.R..."#.... */
|
---|
394 | 0x16, 0x86, 0xca, 0xa0, 0xa7, 0x34, 0xfb, 0xbc, /* 0x000004a0: .....4.. */
|
---|
395 | };
|
---|
396 |
|
---|
397 | #endif /* RT_OS_WINDOWS */
|
---|
398 |
|
---|
399 |
|
---|
400 | /**
|
---|
401 | * Certificate w/ public key + private key pair for signing.
|
---|
402 | */
|
---|
403 | class SignToolKeyPair
|
---|
404 | {
|
---|
405 | protected:
|
---|
406 | /* Context: */
|
---|
407 | const char *m_pszWhat;
|
---|
408 | bool m_fMandatory;
|
---|
409 |
|
---|
410 | /* Parameters kept till finalizing parsing: */
|
---|
411 | const char *m_pszCertFile;
|
---|
412 | const char *m_pszCertSha1;
|
---|
413 | uint8_t m_abCertSha1[RTSHA1_HASH_SIZE];
|
---|
414 | const char *m_pszCertSubject;
|
---|
415 | const char *m_pszCertStore;
|
---|
416 | bool m_fMachineStore; /**< false = personal store */
|
---|
417 |
|
---|
418 | const char *m_pszKeyFile;
|
---|
419 | const char *m_pszKeyPassword;
|
---|
420 | const char *m_pszKeyName;
|
---|
421 | const char *m_pszKeyProvider;
|
---|
422 |
|
---|
423 | /** String buffer for m_pszKeyPassword when read from file. */
|
---|
424 | RTCString m_strPassword;
|
---|
425 | /** Storage for pCertificate when it's loaded from a file. */
|
---|
426 | RTCRX509CERTIFICATE m_DecodedCert;
|
---|
427 | #ifdef RT_OS_WINDOWS
|
---|
428 | /** For the fake certificate */
|
---|
429 | RTCRX509CERTIFICATE m_DecodedFakeCert;
|
---|
430 | /** The certificate store. */
|
---|
431 | HCERTSTORE m_hStore;
|
---|
432 | /** The windows certificate context. */
|
---|
433 | PCCERT_CONTEXT m_pCertCtx;
|
---|
434 | /** Whether hNCryptPrivateKey/hLegacyPrivateKey needs freeing or not. */
|
---|
435 | BOOL m_fFreePrivateHandle;
|
---|
436 | #endif
|
---|
437 |
|
---|
438 | /** Set if already finalized. */
|
---|
439 | bool m_fFinalized;
|
---|
440 |
|
---|
441 | /** Store containing the intermediate certificates available to the host.
|
---|
442 | * */
|
---|
443 | static RTCRSTORE s_hStoreIntermediate;
|
---|
444 | /** Instance counter for helping cleaning up m_hStoreIntermediate. */
|
---|
445 | static uint32_t s_cInstances;
|
---|
446 |
|
---|
447 | public: /* used to be a struct, thus not prefix either. */
|
---|
448 | /* Result: */
|
---|
449 | PCRTCRX509CERTIFICATE pCertificate;
|
---|
450 | RTCRKEY hPrivateKey;
|
---|
451 | #ifdef RT_OS_WINDOWS
|
---|
452 | PCRTCRX509CERTIFICATE pCertificateReal;
|
---|
453 | NCRYPT_KEY_HANDLE hNCryptPrivateKey;
|
---|
454 | HCRYPTPROV hLegacyPrivateKey;
|
---|
455 | #endif
|
---|
456 |
|
---|
457 | public:
|
---|
458 | SignToolKeyPair(const char *a_pszWhat, bool a_fMandatory = false)
|
---|
459 | : m_pszWhat(a_pszWhat)
|
---|
460 | , m_fMandatory(a_fMandatory)
|
---|
461 | , m_pszCertFile(NULL)
|
---|
462 | , m_pszCertSha1(NULL)
|
---|
463 | , m_pszCertSubject(NULL)
|
---|
464 | , m_pszCertStore("MY")
|
---|
465 | , m_fMachineStore(false)
|
---|
466 | , m_pszKeyFile(NULL)
|
---|
467 | , m_pszKeyPassword(NULL)
|
---|
468 | , m_pszKeyName(NULL)
|
---|
469 | , m_pszKeyProvider(NULL)
|
---|
470 | #ifdef RT_OS_WINDOWS
|
---|
471 | , m_hStore(NULL)
|
---|
472 | , m_pCertCtx(NULL)
|
---|
473 | , m_fFreePrivateHandle(FALSE)
|
---|
474 | #endif
|
---|
475 | , m_fFinalized(false)
|
---|
476 | , pCertificate(NULL)
|
---|
477 | , hPrivateKey(NIL_RTCRKEY)
|
---|
478 | #ifdef RT_OS_WINDOWS
|
---|
479 | , pCertificateReal(NULL)
|
---|
480 | , hNCryptPrivateKey(0)
|
---|
481 | , hLegacyPrivateKey(0)
|
---|
482 | #endif
|
---|
483 | {
|
---|
484 | RT_ZERO(m_DecodedCert);
|
---|
485 | #ifdef RT_OS_WINDOWS
|
---|
486 | RT_ZERO(m_DecodedFakeCert);
|
---|
487 | #endif
|
---|
488 | s_cInstances++;
|
---|
489 | }
|
---|
490 |
|
---|
491 | virtual ~SignToolKeyPair()
|
---|
492 | {
|
---|
493 | if (hPrivateKey != NIL_RTCRKEY)
|
---|
494 | {
|
---|
495 | RTCrKeyRelease(hPrivateKey);
|
---|
496 | hPrivateKey = NIL_RTCRKEY;
|
---|
497 | }
|
---|
498 | if (pCertificate == &m_DecodedCert)
|
---|
499 | {
|
---|
500 | RTCrX509Certificate_Delete(&m_DecodedCert);
|
---|
501 | pCertificate = NULL;
|
---|
502 | }
|
---|
503 | #ifdef RT_OS_WINDOWS
|
---|
504 | if (pCertificate == &m_DecodedFakeCert)
|
---|
505 | {
|
---|
506 | RTCrX509Certificate_Delete(&m_DecodedFakeCert);
|
---|
507 | RTCrX509Certificate_Delete(&m_DecodedCert);
|
---|
508 | pCertificate = NULL;
|
---|
509 | pCertificateReal = NULL;
|
---|
510 | }
|
---|
511 | #endif
|
---|
512 | #ifdef RT_OS_WINDOWS
|
---|
513 | if (m_pCertCtx != NULL)
|
---|
514 | {
|
---|
515 | CertFreeCertificateContext(m_pCertCtx);
|
---|
516 | m_pCertCtx = NULL;
|
---|
517 | }
|
---|
518 | if (m_hStore != NULL)
|
---|
519 | {
|
---|
520 | CertCloseStore(m_hStore, 0);
|
---|
521 | m_hStore = NULL;
|
---|
522 | }
|
---|
523 | #endif
|
---|
524 | s_cInstances--;
|
---|
525 | if (s_cInstances == 0)
|
---|
526 | {
|
---|
527 | RTCrStoreRelease(s_hStoreIntermediate);
|
---|
528 | s_hStoreIntermediate = NIL_RTCRSTORE;
|
---|
529 | }
|
---|
530 | }
|
---|
531 |
|
---|
532 | bool isComplete(void) const
|
---|
533 | {
|
---|
534 | return pCertificate && hPrivateKey != NIL_RTCRKEY;
|
---|
535 | }
|
---|
536 |
|
---|
537 | bool isNull(void) const
|
---|
538 | {
|
---|
539 | return pCertificate == NULL && hPrivateKey == NIL_RTCRKEY;
|
---|
540 | }
|
---|
541 |
|
---|
542 | RTEXITCODE handleOption(unsigned offOpt, PRTGETOPTUNION pValueUnion)
|
---|
543 | {
|
---|
544 | AssertReturn(!m_fFinalized, RTMsgErrorExitFailure("Cannot handle options after finalizeOptions was called!"));
|
---|
545 | switch (offOpt)
|
---|
546 | {
|
---|
547 | case OPT_OFF_CERT_FILE:
|
---|
548 | m_pszCertFile = pValueUnion->psz;
|
---|
549 | m_pszCertSha1 = NULL;
|
---|
550 | m_pszCertSubject = NULL;
|
---|
551 | break;
|
---|
552 | case OPT_OFF_CERT_SHA1:
|
---|
553 | {
|
---|
554 | /* Crude normalization of input separators to colons, since it's likely
|
---|
555 | to use spaces and our conversion function only does colons or nothing. */
|
---|
556 | char szDigest[RTSHA1_DIGEST_LEN * 3 + 1];
|
---|
557 | int rc = RTStrCopy(szDigest, sizeof(szDigest), pValueUnion->psz);
|
---|
558 | if (RT_SUCCESS(rc))
|
---|
559 | {
|
---|
560 | char *pszDigest = RTStrStrip(szDigest);
|
---|
561 | size_t offDst = 0;
|
---|
562 | size_t offSrc = 0;
|
---|
563 | char ch;
|
---|
564 | while ((ch = pszDigest[offSrc++]) != '\0')
|
---|
565 | {
|
---|
566 | if (ch == ' ' || ch == '\t' || ch == ':')
|
---|
567 | {
|
---|
568 | while ((ch = pszDigest[offSrc]) == ' ' || ch == '\t' || ch == ':')
|
---|
569 | offSrc++;
|
---|
570 | ch = ch ? ':' : '\0';
|
---|
571 | }
|
---|
572 | pszDigest[offDst++] = ch;
|
---|
573 | }
|
---|
574 | pszDigest[offDst] = '\0';
|
---|
575 |
|
---|
576 | /** @todo add a more relaxed input mode to RTStrConvertHexBytes that can deal
|
---|
577 | * with spaces as well as multi-byte cluster of inputs. */
|
---|
578 | rc = RTStrConvertHexBytes(pszDigest, m_abCertSha1, RTSHA1_HASH_SIZE, RTSTRCONVERTHEXBYTES_F_SEP_COLON);
|
---|
579 | if (RT_SUCCESS(rc))
|
---|
580 | {
|
---|
581 | m_pszCertFile = NULL;
|
---|
582 | m_pszCertSha1 = pValueUnion->psz;
|
---|
583 | m_pszCertSubject = NULL;
|
---|
584 | break;
|
---|
585 | }
|
---|
586 | }
|
---|
587 | return RTMsgErrorExitFailure("malformed SHA-1 certificate fingerprint (%Rrc): %s", rc, pValueUnion->psz);
|
---|
588 | }
|
---|
589 | case OPT_OFF_CERT_SUBJECT:
|
---|
590 | m_pszCertFile = NULL;
|
---|
591 | m_pszCertSha1 = NULL;
|
---|
592 | m_pszCertSubject = pValueUnion->psz;
|
---|
593 | break;
|
---|
594 | case OPT_OFF_CERT_STORE:
|
---|
595 | m_pszCertStore = pValueUnion->psz;
|
---|
596 | break;
|
---|
597 | case OPT_OFF_CERT_STORE_MACHINE:
|
---|
598 | m_fMachineStore = true;
|
---|
599 | break;
|
---|
600 |
|
---|
601 | case OPT_OFF_KEY_FILE:
|
---|
602 | m_pszKeyFile = pValueUnion->psz;
|
---|
603 | m_pszKeyName = NULL;
|
---|
604 | break;
|
---|
605 | case OPT_OFF_KEY_NAME:
|
---|
606 | m_pszKeyFile = NULL;
|
---|
607 | m_pszKeyName = pValueUnion->psz;
|
---|
608 | break;
|
---|
609 | case OPT_OFF_KEY_PROVIDER:
|
---|
610 | m_pszKeyProvider = pValueUnion->psz;
|
---|
611 | break;
|
---|
612 | case OPT_OFF_KEY_PASSWORD:
|
---|
613 | m_pszKeyPassword = pValueUnion->psz;
|
---|
614 | break;
|
---|
615 | case OPT_OFF_KEY_PASSWORD_FILE:
|
---|
616 | {
|
---|
617 | m_pszKeyPassword = NULL;
|
---|
618 |
|
---|
619 | size_t const cchMax = 512;
|
---|
620 | int rc = m_strPassword.reserveNoThrow(cchMax + 1);
|
---|
621 | if (RT_FAILURE(rc))
|
---|
622 | return RTMsgErrorExitFailure("out of memory");
|
---|
623 |
|
---|
624 | PRTSTREAM pStrm = g_pStdIn;
|
---|
625 | bool const fClose = strcmp(pValueUnion->psz, "stdin") != 0;
|
---|
626 | if (fClose)
|
---|
627 | {
|
---|
628 | rc = RTStrmOpen(pValueUnion->psz, "r", &pStrm);
|
---|
629 | if (RT_FAILURE(rc))
|
---|
630 | return RTMsgErrorExitFailure("Failed to open password file '%s' for reading: %Rrc", pValueUnion->psz, rc);
|
---|
631 | }
|
---|
632 | rc = RTStrmGetLine(pStrm, m_strPassword.mutableRaw(), cchMax);
|
---|
633 | if (fClose)
|
---|
634 | RTStrmClose(pStrm);
|
---|
635 | if (rc == VERR_BUFFER_OVERFLOW || rc == VINF_BUFFER_OVERFLOW)
|
---|
636 | return RTMsgErrorExitFailure("Password from '%s' is too long (max %zu)", pValueUnion->psz, cchMax);
|
---|
637 | if (RT_FAILURE(rc))
|
---|
638 | return RTMsgErrorExitFailure("Error reading password from '%s': %Rrc", pValueUnion->psz, rc);
|
---|
639 |
|
---|
640 | m_strPassword.jolt();
|
---|
641 | m_strPassword.stripRight();
|
---|
642 | m_pszKeyPassword = m_strPassword.c_str();
|
---|
643 | break;
|
---|
644 | }
|
---|
645 | default:
|
---|
646 | AssertFailedReturn(RTMsgErrorExitFailure("Invalid offOpt=%u!\n", offOpt));
|
---|
647 | }
|
---|
648 | return RTEXITCODE_SUCCESS;
|
---|
649 | }
|
---|
650 |
|
---|
651 | RTEXITCODE finalizeOptions(unsigned cVerbosity)
|
---|
652 | {
|
---|
653 | RT_NOREF(cVerbosity);
|
---|
654 |
|
---|
655 | /* Only do this once. */
|
---|
656 | if (m_fFinalized)
|
---|
657 | return RTEXITCODE_SUCCESS;
|
---|
658 | m_fFinalized = true;
|
---|
659 |
|
---|
660 | /*
|
---|
661 | * Got a cert? Is it required?
|
---|
662 | */
|
---|
663 | bool const fHasKey = ( m_pszKeyFile != NULL
|
---|
664 | || m_pszKeyName != NULL);
|
---|
665 | bool const fHasCert = ( m_pszCertFile != NULL
|
---|
666 | || m_pszCertSha1 != NULL
|
---|
667 | || m_pszCertSubject != NULL);
|
---|
668 | if (!fHasCert)
|
---|
669 | {
|
---|
670 | if (m_fMandatory)
|
---|
671 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Specifying a %s certificiate is required.", m_pszWhat);
|
---|
672 | return RTEXITCODE_SUCCESS;
|
---|
673 | }
|
---|
674 |
|
---|
675 | /*
|
---|
676 | * Get the certificate.
|
---|
677 | */
|
---|
678 | RTERRINFOSTATIC ErrInfo;
|
---|
679 | /* From file: */
|
---|
680 | if (m_pszCertFile)
|
---|
681 | {
|
---|
682 | int rc = RTCrX509Certificate_ReadFromFile(&m_DecodedCert, m_pszCertFile, 0, &g_RTAsn1DefaultAllocator,
|
---|
683 | RTErrInfoInitStatic(&ErrInfo));
|
---|
684 | if (RT_FAILURE(rc))
|
---|
685 | return RTMsgErrorExitFailure("Error reading %s certificate from '%s': %Rrc%#RTeim",
|
---|
686 | m_pszWhat, m_pszCertFile, rc, &ErrInfo.Core);
|
---|
687 | pCertificate = &m_DecodedCert;
|
---|
688 | }
|
---|
689 | /* From certificate store by name (substring) or fingerprint: */
|
---|
690 | else
|
---|
691 | {
|
---|
692 | #ifdef RT_OS_WINDOWS
|
---|
693 | m_hStore = CertOpenStore(CERT_STORE_PROV_SYSTEM_A, X509_ASN_ENCODING, NULL,
|
---|
694 | CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG | CERT_STORE_READONLY_FLAG
|
---|
695 | | CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_ENUM_ARCHIVED_FLAG
|
---|
696 | | (m_fMachineStore ? CERT_SYSTEM_STORE_LOCAL_MACHINE : CERT_SYSTEM_STORE_CURRENT_USER),
|
---|
697 | m_pszCertStore);
|
---|
698 | if (m_hStore == NULL)
|
---|
699 | return RTMsgErrorExitFailure("Failed to open %s store '%s': %Rwc (%u)", m_fMachineStore ? "machine" : "user",
|
---|
700 | m_pszCertStore, GetLastError(), GetLastError());
|
---|
701 |
|
---|
702 | CRYPT_HASH_BLOB Thumbprint = { RTSHA1_HASH_SIZE, m_abCertSha1 };
|
---|
703 | PRTUTF16 pwszSubject = NULL;
|
---|
704 | void const *pvFindParam = &Thumbprint;
|
---|
705 | DWORD fFind = CERT_FIND_SHA1_HASH;
|
---|
706 | if (!m_pszCertSha1)
|
---|
707 | {
|
---|
708 | int rc = RTStrToUtf16(m_pszCertSubject, &pwszSubject);
|
---|
709 | if (RT_FAILURE(rc))
|
---|
710 | return RTMsgErrorExitFailure("RTStrToUtf16 failed: %Rrc, input %.*Rhxs",
|
---|
711 | rc, strlen(m_pszCertSubject), m_pszCertSubject);
|
---|
712 | pvFindParam = pwszSubject;
|
---|
713 | fFind = CERT_FIND_SUBJECT_STR;
|
---|
714 | }
|
---|
715 |
|
---|
716 | while ((m_pCertCtx = CertFindCertificateInStore(m_hStore, X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, 0 /*fFlags*/,
|
---|
717 | fFind, pvFindParam, m_pCertCtx)) != NULL)
|
---|
718 | {
|
---|
719 | if (m_pCertCtx->dwCertEncodingType & X509_ASN_ENCODING)
|
---|
720 | {
|
---|
721 | RTASN1CURSORPRIMARY PrimaryCursor;
|
---|
722 | RTAsn1CursorInitPrimary(&PrimaryCursor, m_pCertCtx->pbCertEncoded, m_pCertCtx->cbCertEncoded,
|
---|
723 | RTErrInfoInitStatic(&ErrInfo),
|
---|
724 | &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "CurCtx");
|
---|
725 | int rc = RTCrX509Certificate_DecodeAsn1(&PrimaryCursor.Cursor, 0, &m_DecodedCert, "Cert");
|
---|
726 | if (RT_SUCCESS(rc))
|
---|
727 | {
|
---|
728 | pCertificate = &m_DecodedCert;
|
---|
729 | break;
|
---|
730 | }
|
---|
731 | RTMsgError("failed to decode certificate %p: %Rrc%#RTeim", m_pCertCtx, rc, &ErrInfo.Core);
|
---|
732 | }
|
---|
733 | }
|
---|
734 |
|
---|
735 | RTUtf16Free(pwszSubject);
|
---|
736 | if (!m_pCertCtx)
|
---|
737 | return RTMsgErrorExitFailure("No certificate found matching %s '%s' (%Rwc / %u)",
|
---|
738 | m_pszCertSha1 ? "thumbprint" : "subject substring",
|
---|
739 | m_pszCertSha1 ? m_pszCertSha1 : m_pszCertSubject, GetLastError(), GetLastError());
|
---|
740 |
|
---|
741 | /* Use this for private key too? */
|
---|
742 | if (!fHasKey)
|
---|
743 | {
|
---|
744 | HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hTmpPrivateKey = 0;
|
---|
745 | DWORD dwKeySpec = 0;
|
---|
746 | if (CryptAcquireCertificatePrivateKey(m_pCertCtx,
|
---|
747 | CRYPT_ACQUIRE_SILENT_FLAG | CRYPT_ACQUIRE_COMPARE_KEY_FLAG
|
---|
748 | | CRYPT_ACQUIRE_ALLOW_NCRYPT_KEY_FLAG
|
---|
749 | | CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG,
|
---|
750 | NULL, &hTmpPrivateKey, &dwKeySpec, &m_fFreePrivateHandle))
|
---|
751 | {
|
---|
752 | if (cVerbosity > 1)
|
---|
753 | RTMsgInfo("hTmpPrivateKey=%p m_fFreePrivateHandle=%d dwKeySpec=%#x",
|
---|
754 | hTmpPrivateKey, m_fFreePrivateHandle, dwKeySpec);
|
---|
755 | Assert(dwKeySpec == CERT_NCRYPT_KEY_SPEC);
|
---|
756 | if (dwKeySpec == CERT_NCRYPT_KEY_SPEC)
|
---|
757 | hNCryptPrivateKey = hTmpPrivateKey;
|
---|
758 | else
|
---|
759 | hLegacyPrivateKey = hTmpPrivateKey; /** @todo remove or drop CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG */
|
---|
760 | return loadFakePrivateKeyAndCert();
|
---|
761 | }
|
---|
762 | return RTMsgErrorExitFailure("CryptAcquireCertificatePrivateKey failed: %Rwc (%d)", GetLastError(), GetLastError());
|
---|
763 | }
|
---|
764 | #else
|
---|
765 | return RTMsgErrorExitFailure("Certificate store support is missing on this host");
|
---|
766 | #endif
|
---|
767 | }
|
---|
768 |
|
---|
769 | /*
|
---|
770 | * Get hold of the private key (if someone above already did, they'd returned already).
|
---|
771 | */
|
---|
772 | Assert(hPrivateKey == NIL_RTCRKEY);
|
---|
773 | /* Use cert file if nothing else specified. */
|
---|
774 | if (!fHasKey && m_pszCertFile)
|
---|
775 | m_pszKeyFile = m_pszCertFile;
|
---|
776 |
|
---|
777 | /* Load from file:*/
|
---|
778 | if (m_pszKeyFile)
|
---|
779 | {
|
---|
780 | int rc = RTCrKeyCreateFromFile(&hPrivateKey, 0 /*fFlags*/, m_pszKeyFile, m_pszKeyPassword,
|
---|
781 | RTErrInfoInitStatic(&ErrInfo));
|
---|
782 | if (RT_FAILURE(rc))
|
---|
783 | return RTMsgErrorExitFailure("Error reading the %s private key from '%s': %Rrc%#RTeim",
|
---|
784 | m_pszWhat, m_pszKeyFile, rc, &ErrInfo.Core);
|
---|
785 | }
|
---|
786 | /* From key store: */
|
---|
787 | else
|
---|
788 | {
|
---|
789 | return RTMsgErrorExitFailure("Key store support is missing on this host");
|
---|
790 | }
|
---|
791 |
|
---|
792 | return RTEXITCODE_SUCCESS;
|
---|
793 | }
|
---|
794 |
|
---|
795 | /** Returns the real certificate. */
|
---|
796 | PCRTCRX509CERTIFICATE getRealCertificate() const
|
---|
797 | {
|
---|
798 | #ifdef RT_OS_WINDOWS
|
---|
799 | if (pCertificateReal)
|
---|
800 | return pCertificateReal;
|
---|
801 | #endif
|
---|
802 | return pCertificate;
|
---|
803 | }
|
---|
804 |
|
---|
805 | #ifdef RT_OS_WINDOWS
|
---|
806 | RTEXITCODE loadFakePrivateKeyAndCert()
|
---|
807 | {
|
---|
808 | int rc = RTCrX509Certificate_ReadFromBuffer(&m_DecodedFakeCert, g_abFakeCertificate, sizeof(g_abFakeCertificate),
|
---|
809 | 0 /*fFlags*/, &g_RTAsn1DefaultAllocator, NULL, NULL);
|
---|
810 | if (RT_FAILURE(rc))
|
---|
811 | return RTMsgErrorExitFailure("RTCrX509Certificate_ReadFromBuffer/g_abFakeCertificate failed: %Rrc", rc);
|
---|
812 | pCertificateReal = pCertificate;
|
---|
813 | pCertificate = &m_DecodedFakeCert;
|
---|
814 |
|
---|
815 | rc = RTCrKeyCreateFromBuffer(&hPrivateKey, 0 /*fFlags*/, g_abFakeRsaKey, sizeof(g_abFakeRsaKey), NULL, NULL, NULL);
|
---|
816 | if (RT_FAILURE(rc))
|
---|
817 | return RTMsgErrorExitFailure("RTCrKeyCreateFromBuffer/g_abFakeRsaKey failed: %Rrc", rc);
|
---|
818 | return RTEXITCODE_SUCCESS;
|
---|
819 | }
|
---|
820 |
|
---|
821 | #endif
|
---|
822 |
|
---|
823 | /**
|
---|
824 | * Search for intermediate CA.
|
---|
825 | *
|
---|
826 | * Currently this only do a single certificate path, so this may go south if
|
---|
827 | * there are multiple paths available. It may work fine for a cross signing
|
---|
828 | * path, as long as the cross over is at the level immediately below the root.
|
---|
829 | */
|
---|
830 | PCRTCRCERTCTX findNextIntermediateCert(PCRTCRCERTCTX pPrev)
|
---|
831 | {
|
---|
832 | /*
|
---|
833 | * Make sure the store is loaded before we start.
|
---|
834 | */
|
---|
835 | if (s_hStoreIntermediate == NIL_RTCRSTORE)
|
---|
836 | {
|
---|
837 | Assert(!pPrev);
|
---|
838 | RTERRINFOSTATIC ErrInfo;
|
---|
839 | int rc = RTCrStoreCreateSnapshotById(&s_hStoreIntermediate,
|
---|
840 | !m_fMachineStore
|
---|
841 | ? RTCRSTOREID_USER_INTERMEDIATE_CAS : RTCRSTOREID_SYSTEM_INTERMEDIATE_CAS,
|
---|
842 | RTErrInfoInitStatic(&ErrInfo));
|
---|
843 | if (RT_FAILURE(rc))
|
---|
844 | {
|
---|
845 | RTMsgError("RTCrStoreCreateSnapshotById/%s-intermediate-CAs failed: %Rrc%#RTeim",
|
---|
846 | m_fMachineStore ? "user" : "machine", rc, &ErrInfo.Core);
|
---|
847 | return NULL;
|
---|
848 | }
|
---|
849 | }
|
---|
850 |
|
---|
851 | /*
|
---|
852 | * Open the search handle for the parent of the previous/end certificate.
|
---|
853 | *
|
---|
854 | * We don't need to consider RTCRCERTCTX::pTaInfo here as we're not
|
---|
855 | * after trust anchors, only intermediate certificates.
|
---|
856 | */
|
---|
857 | #ifdef RT_OS_WINDOWS
|
---|
858 | PCRTCRX509CERTIFICATE pChildCert = pPrev ? pPrev->pCert : pCertificateReal ? pCertificateReal : pCertificate;
|
---|
859 | #else
|
---|
860 | PCRTCRX509CERTIFICATE pChildCert = pPrev ? pPrev->pCert : pCertificate;
|
---|
861 | #endif
|
---|
862 | AssertReturnStmt(pChildCert, RTCrCertCtxRelease(pPrev), NULL);
|
---|
863 |
|
---|
864 | RTCRSTORECERTSEARCH Search;
|
---|
865 | int rc = RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(s_hStoreIntermediate, &pChildCert->TbsCertificate.Issuer,
|
---|
866 | &Search);
|
---|
867 | if (RT_FAILURE(rc))
|
---|
868 | {
|
---|
869 | RTMsgError("RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280 failed: %Rrc", rc);
|
---|
870 | return NULL;
|
---|
871 | }
|
---|
872 |
|
---|
873 | /*
|
---|
874 | * We only gave the subject so, we have to check the serial number our selves.
|
---|
875 | */
|
---|
876 | PCRTCRCERTCTX pCertCtx;
|
---|
877 | while ((pCertCtx = RTCrStoreCertSearchNext(s_hStoreIntermediate, &Search)) != NULL)
|
---|
878 | {
|
---|
879 | if ( pCertCtx->pCert
|
---|
880 | && RTAsn1BitString_Compare(&pCertCtx->pCert->TbsCertificate.T1.IssuerUniqueId,
|
---|
881 | &pChildCert->TbsCertificate.T1.IssuerUniqueId) == 0 /* compares presentness too */
|
---|
882 | && !RTCrX509Certificate_IsSelfSigned(pCertCtx->pCert))
|
---|
883 | {
|
---|
884 | break; /** @todo compare valid periode too and keep a best match when outside the desired period? */
|
---|
885 | }
|
---|
886 | RTCrCertCtxRelease(pCertCtx);
|
---|
887 | }
|
---|
888 |
|
---|
889 | RTCrStoreCertSearchDestroy(s_hStoreIntermediate, & Search);
|
---|
890 | RTCrCertCtxRelease(pPrev);
|
---|
891 | return pCertCtx;
|
---|
892 | }
|
---|
893 |
|
---|
894 | /**
|
---|
895 | * Merges the user specified certificates with the signing certificate and any
|
---|
896 | * intermediate CAs we can find in the system store.
|
---|
897 | *
|
---|
898 | * @returns Merged store, NIL_RTCRSTORE on failure (messaged).
|
---|
899 | * @param hUserSpecifiedCertificates The user certificate store.
|
---|
900 | */
|
---|
901 | RTCRSTORE assembleAllAdditionalCertificates(RTCRSTORE hUserSpecifiedCertificates)
|
---|
902 | {
|
---|
903 | RTCRSTORE hRetStore;
|
---|
904 | int rc = RTCrStoreCreateInMemEx(&hRetStore, 0, hUserSpecifiedCertificates);
|
---|
905 | if (RT_SUCCESS(rc))
|
---|
906 | {
|
---|
907 | /* Add the signing certificate: */
|
---|
908 | RTERRINFOSTATIC ErrInfo;
|
---|
909 | rc = RTCrStoreCertAddX509(hRetStore, RTCRCERTCTX_F_ENC_X509_DER | RTCRCERTCTX_F_ADD_IF_NOT_FOUND,
|
---|
910 | #ifdef RT_OS_WINDOWS
|
---|
911 | (PRTCRX509CERTIFICATE)(pCertificateReal ? pCertificateReal : pCertificate),
|
---|
912 | #else
|
---|
913 | (PRTCRX509CERTIFICATE)pCertificate,
|
---|
914 | #endif
|
---|
915 | RTErrInfoInitStatic(&ErrInfo));
|
---|
916 | if (RT_SUCCESS(rc))
|
---|
917 | {
|
---|
918 | /* Add all intermediate CAs certificates we can find. */
|
---|
919 | PCRTCRCERTCTX pInterCaCert = NULL;
|
---|
920 | while ((pInterCaCert = findNextIntermediateCert(pInterCaCert)) != NULL)
|
---|
921 | {
|
---|
922 | rc = RTCrStoreCertAddEncoded(hRetStore, RTCRCERTCTX_F_ENC_X509_DER | RTCRCERTCTX_F_ADD_IF_NOT_FOUND,
|
---|
923 | pInterCaCert->pabEncoded, pInterCaCert->cbEncoded,
|
---|
924 | RTErrInfoInitStatic(&ErrInfo));
|
---|
925 | if (RT_FAILURE(rc))
|
---|
926 | {
|
---|
927 | RTMsgError("RTCrStoreCertAddEncoded/InterCA failed: %Rrc%#RTeim", rc, &ErrInfo.Core);
|
---|
928 | RTCrCertCtxRelease(pInterCaCert);
|
---|
929 | break;
|
---|
930 | }
|
---|
931 | }
|
---|
932 | if (RT_SUCCESS(rc))
|
---|
933 | return hRetStore;
|
---|
934 | }
|
---|
935 | else
|
---|
936 | RTMsgError("RTCrStoreCertAddX509/signer failed: %Rrc%#RTeim", rc, &ErrInfo.Core);
|
---|
937 | RTCrStoreRelease(hRetStore);
|
---|
938 | }
|
---|
939 | else
|
---|
940 | RTMsgError("RTCrStoreCreateInMemEx failed: %Rrc", rc);
|
---|
941 | return NIL_RTCRSTORE;
|
---|
942 | }
|
---|
943 |
|
---|
944 | };
|
---|
945 |
|
---|
946 | /*static*/ RTCRSTORE SignToolKeyPair::s_hStoreIntermediate = NIL_RTCRSTORE;
|
---|
947 | /*static*/ uint32_t SignToolKeyPair::s_cInstances = 0;
|
---|
948 |
|
---|
949 |
|
---|
950 | /*********************************************************************************************************************************
|
---|
951 | *
|
---|
952 | *********************************************************************************************************************************/
|
---|
953 | /** Timestamp type. */
|
---|
954 | typedef enum
|
---|
955 | {
|
---|
956 | /** Old timestamp style.
|
---|
957 | * This is just a counter signature with a trustworthy SigningTime attribute.
|
---|
958 | * Specificially it's the SignerInfo part of a detached PKCS#7 covering the
|
---|
959 | * SignerInfo.EncryptedDigest. */
|
---|
960 | kTimestampType_Old = 1,
|
---|
961 | /** This is a whole PKCS#7 signature of an TSTInfo from RFC-3161 (see page 7).
|
---|
962 | * Currently not supported. */
|
---|
963 | kTimestampType_New
|
---|
964 | } TIMESTAMPTYPE;
|
---|
965 |
|
---|
966 | /**
|
---|
967 | * Timestamping options.
|
---|
968 | *
|
---|
969 | * Certificate w/ public key + private key pair for signing and signature type.
|
---|
970 | */
|
---|
971 | class SignToolTimestampOpts : public SignToolKeyPair
|
---|
972 | {
|
---|
973 | public:
|
---|
974 | /** Type timestamp type. */
|
---|
975 | TIMESTAMPTYPE m_enmType;
|
---|
976 |
|
---|
977 | SignToolTimestampOpts(const char *a_pszWhat, TIMESTAMPTYPE a_enmType = kTimestampType_Old)
|
---|
978 | : SignToolKeyPair(a_pszWhat)
|
---|
979 | , m_enmType(a_enmType)
|
---|
980 | {
|
---|
981 | }
|
---|
982 |
|
---|
983 | bool isOldType() const { return m_enmType == kTimestampType_Old; }
|
---|
984 | bool isNewType() const { return m_enmType == kTimestampType_New; }
|
---|
985 | };
|
---|
986 |
|
---|
987 |
|
---|
988 |
|
---|
989 | /*********************************************************************************************************************************
|
---|
990 | * Crypto Store Auto Cleanup Wrapper. *
|
---|
991 | *********************************************************************************************************************************/
|
---|
992 | class CryptoStore
|
---|
993 | {
|
---|
994 | public:
|
---|
995 | RTCRSTORE m_hStore;
|
---|
996 |
|
---|
997 | CryptoStore()
|
---|
998 | : m_hStore(NIL_RTCRSTORE)
|
---|
999 | {
|
---|
1000 | }
|
---|
1001 |
|
---|
1002 | ~CryptoStore()
|
---|
1003 | {
|
---|
1004 | if (m_hStore != NIL_RTCRSTORE)
|
---|
1005 | {
|
---|
1006 | uint32_t cRefs = RTCrStoreRelease(m_hStore);
|
---|
1007 | Assert(cRefs == 0); RT_NOREF(cRefs);
|
---|
1008 | m_hStore = NIL_RTCRSTORE;
|
---|
1009 | }
|
---|
1010 | }
|
---|
1011 |
|
---|
1012 | /**
|
---|
1013 | * Adds one or more certificates from the given file.
|
---|
1014 | *
|
---|
1015 | * @returns boolean success indicator.
|
---|
1016 | */
|
---|
1017 | bool addFromFile(const char *pszFilename, PRTERRINFOSTATIC pStaticErrInfo)
|
---|
1018 | {
|
---|
1019 | int rc = RTCrStoreCertAddFromFile(this->m_hStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
|
---|
1020 | pszFilename, RTErrInfoInitStatic(pStaticErrInfo));
|
---|
1021 | if (RT_SUCCESS(rc))
|
---|
1022 | {
|
---|
1023 | if (RTErrInfoIsSet(&pStaticErrInfo->Core))
|
---|
1024 | RTMsgWarning("Warnings loading certificate '%s': %s", pszFilename, pStaticErrInfo->Core.pszMsg);
|
---|
1025 | return true;
|
---|
1026 | }
|
---|
1027 | RTMsgError("Error loading certificate '%s': %Rrc%#RTeim", pszFilename, rc, &pStaticErrInfo->Core);
|
---|
1028 | return false;
|
---|
1029 | }
|
---|
1030 |
|
---|
1031 | /**
|
---|
1032 | * Adds trusted self-signed certificates from the system.
|
---|
1033 | *
|
---|
1034 | * @returns boolean success indicator.
|
---|
1035 | * @note The selection is self-signed rather than CAs here so that test signing
|
---|
1036 | * certificates will be included.
|
---|
1037 | */
|
---|
1038 | bool addSelfSignedRootsFromSystem(PRTERRINFOSTATIC pStaticErrInfo)
|
---|
1039 | {
|
---|
1040 | CryptoStore Tmp;
|
---|
1041 | int rc = RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts(&Tmp.m_hStore, RTErrInfoInitStatic(pStaticErrInfo));
|
---|
1042 | if (RT_SUCCESS(rc))
|
---|
1043 | {
|
---|
1044 | RTCRSTORECERTSEARCH Search;
|
---|
1045 | rc = RTCrStoreCertFindAll(Tmp.m_hStore, &Search);
|
---|
1046 | if (RT_SUCCESS(rc))
|
---|
1047 | {
|
---|
1048 | PCRTCRCERTCTX pCertCtx;
|
---|
1049 | while ((pCertCtx = RTCrStoreCertSearchNext(Tmp.m_hStore, &Search)) != NULL)
|
---|
1050 | {
|
---|
1051 | /* Add it if it's a full fledged self-signed certificate, otherwise just skip: */
|
---|
1052 | if ( pCertCtx->pCert
|
---|
1053 | && RTCrX509Certificate_IsSelfSigned(pCertCtx->pCert))
|
---|
1054 | {
|
---|
1055 | int rc2 = RTCrStoreCertAddEncoded(this->m_hStore,
|
---|
1056 | pCertCtx->fFlags | RTCRCERTCTX_F_ADD_IF_NOT_FOUND,
|
---|
1057 | pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL);
|
---|
1058 | if (RT_FAILURE(rc2))
|
---|
1059 | RTMsgWarning("RTCrStoreCertAddEncoded failed for a certificate: %Rrc", rc2);
|
---|
1060 | }
|
---|
1061 | RTCrCertCtxRelease(pCertCtx);
|
---|
1062 | }
|
---|
1063 |
|
---|
1064 | int rc2 = RTCrStoreCertSearchDestroy(Tmp.m_hStore, &Search);
|
---|
1065 | AssertRC(rc2);
|
---|
1066 | return true;
|
---|
1067 | }
|
---|
1068 | RTMsgError("RTCrStoreCertFindAll failed: %Rrc", rc);
|
---|
1069 | }
|
---|
1070 | else
|
---|
1071 | RTMsgError("RTCrStoreCreateSnapshotOfUserAndSystemTrustedCAsAndCerts failed: %Rrc%#RTeim", rc, &pStaticErrInfo->Core);
|
---|
1072 | return false;
|
---|
1073 | }
|
---|
1074 |
|
---|
1075 | /**
|
---|
1076 | * Adds trusted self-signed certificates from the system.
|
---|
1077 | *
|
---|
1078 | * @returns boolean success indicator.
|
---|
1079 | */
|
---|
1080 | bool addIntermediateCertsFromSystem(PRTERRINFOSTATIC pStaticErrInfo)
|
---|
1081 | {
|
---|
1082 | bool fRc = true;
|
---|
1083 | RTCRSTOREID const s_aenmStoreIds[] = { RTCRSTOREID_SYSTEM_INTERMEDIATE_CAS, RTCRSTOREID_USER_INTERMEDIATE_CAS };
|
---|
1084 | for (size_t i = 0; i < RT_ELEMENTS(s_aenmStoreIds); i++)
|
---|
1085 | {
|
---|
1086 | CryptoStore Tmp;
|
---|
1087 | int rc = RTCrStoreCreateSnapshotById(&Tmp.m_hStore, s_aenmStoreIds[i], RTErrInfoInitStatic(pStaticErrInfo));
|
---|
1088 | if (RT_SUCCESS(rc))
|
---|
1089 | {
|
---|
1090 | RTCRSTORECERTSEARCH Search;
|
---|
1091 | rc = RTCrStoreCertFindAll(Tmp.m_hStore, &Search);
|
---|
1092 | if (RT_SUCCESS(rc))
|
---|
1093 | {
|
---|
1094 | PCRTCRCERTCTX pCertCtx;
|
---|
1095 | while ((pCertCtx = RTCrStoreCertSearchNext(Tmp.m_hStore, &Search)) != NULL)
|
---|
1096 | {
|
---|
1097 | /* Skip selfsigned certs as they're useless as intermediate certs (IIRC). */
|
---|
1098 | if ( pCertCtx->pCert
|
---|
1099 | && !RTCrX509Certificate_IsSelfSigned(pCertCtx->pCert))
|
---|
1100 | {
|
---|
1101 | int rc2 = RTCrStoreCertAddEncoded(this->m_hStore,
|
---|
1102 | pCertCtx->fFlags | RTCRCERTCTX_F_ADD_IF_NOT_FOUND,
|
---|
1103 | pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL);
|
---|
1104 | if (RT_FAILURE(rc2))
|
---|
1105 | RTMsgWarning("RTCrStoreCertAddEncoded failed for a certificate: %Rrc", rc2);
|
---|
1106 | }
|
---|
1107 | RTCrCertCtxRelease(pCertCtx);
|
---|
1108 | }
|
---|
1109 |
|
---|
1110 | int rc2 = RTCrStoreCertSearchDestroy(Tmp.m_hStore, &Search);
|
---|
1111 | AssertRC(rc2);
|
---|
1112 | }
|
---|
1113 | else
|
---|
1114 | {
|
---|
1115 | RTMsgError("RTCrStoreCertFindAll/%d failed: %Rrc", s_aenmStoreIds[i], rc);
|
---|
1116 | fRc = false;
|
---|
1117 | }
|
---|
1118 | }
|
---|
1119 | else
|
---|
1120 | {
|
---|
1121 | RTMsgError("RTCrStoreCreateSnapshotById/%d failed: %Rrc%#RTeim", s_aenmStoreIds[i], rc, &pStaticErrInfo->Core);
|
---|
1122 | fRc = false;
|
---|
1123 | }
|
---|
1124 | }
|
---|
1125 | return fRc;
|
---|
1126 | }
|
---|
1127 |
|
---|
1128 | };
|
---|
1129 |
|
---|
1130 |
|
---|
1131 |
|
---|
1132 | /*********************************************************************************************************************************
|
---|
1133 | * Workers. *
|
---|
1134 | *********************************************************************************************************************************/
|
---|
1135 |
|
---|
1136 |
|
---|
1137 | /**
|
---|
1138 | * Deletes the structure.
|
---|
1139 | *
|
---|
1140 | * @param pThis The structure to initialize.
|
---|
1141 | */
|
---|
1142 | static void SignToolPkcs7_Delete(PSIGNTOOLPKCS7 pThis)
|
---|
1143 | {
|
---|
1144 | RTCrPkcs7ContentInfo_Delete(&pThis->ContentInfo);
|
---|
1145 | pThis->pSignedData = NULL;
|
---|
1146 | RTMemFree(pThis->pbBuf);
|
---|
1147 | pThis->pbBuf = NULL;
|
---|
1148 | pThis->cbBuf = 0;
|
---|
1149 | RTMemFree(pThis->pbNewBuf);
|
---|
1150 | pThis->pbNewBuf = NULL;
|
---|
1151 | pThis->cbNewBuf = 0;
|
---|
1152 | }
|
---|
1153 |
|
---|
1154 |
|
---|
1155 | /**
|
---|
1156 | * Deletes the structure.
|
---|
1157 | *
|
---|
1158 | * @param pThis The structure to initialize.
|
---|
1159 | */
|
---|
1160 | static void SignToolPkcs7Exe_Delete(PSIGNTOOLPKCS7EXE pThis)
|
---|
1161 | {
|
---|
1162 | if (pThis->hLdrMod != NIL_RTLDRMOD)
|
---|
1163 | {
|
---|
1164 | int rc2 = RTLdrClose(pThis->hLdrMod);
|
---|
1165 | if (RT_FAILURE(rc2))
|
---|
1166 | RTMsgError("RTLdrClose failed: %Rrc\n", rc2);
|
---|
1167 | pThis->hLdrMod = NIL_RTLDRMOD;
|
---|
1168 | }
|
---|
1169 | SignToolPkcs7_Delete(pThis);
|
---|
1170 | }
|
---|
1171 |
|
---|
1172 |
|
---|
1173 | /**
|
---|
1174 | * Decodes the PKCS #7 blob pointed to by pThis->pbBuf.
|
---|
1175 | *
|
---|
1176 | * @returns IPRT status code (error message already shown on failure).
|
---|
1177 | * @param pThis The PKCS\#7 signature to decode.
|
---|
1178 | * @param fCatalog Set if catalog file, clear if executable.
|
---|
1179 | */
|
---|
1180 | static int SignToolPkcs7_Decode(PSIGNTOOLPKCS7 pThis, bool fCatalog)
|
---|
1181 | {
|
---|
1182 | RTERRINFOSTATIC ErrInfo;
|
---|
1183 | RTASN1CURSORPRIMARY PrimaryCursor;
|
---|
1184 | RTAsn1CursorInitPrimary(&PrimaryCursor, pThis->pbBuf, (uint32_t)pThis->cbBuf, RTErrInfoInitStatic(&ErrInfo),
|
---|
1185 | &g_RTAsn1DefaultAllocator, 0, "WinCert");
|
---|
1186 |
|
---|
1187 | int rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, &pThis->ContentInfo, "CI");
|
---|
1188 | if (RT_SUCCESS(rc))
|
---|
1189 | {
|
---|
1190 | if (RTCrPkcs7ContentInfo_IsSignedData(&pThis->ContentInfo))
|
---|
1191 | {
|
---|
1192 | pThis->pSignedData = pThis->ContentInfo.u.pSignedData;
|
---|
1193 |
|
---|
1194 | /*
|
---|
1195 | * Decode the authenticode bits.
|
---|
1196 | */
|
---|
1197 | if (!strcmp(pThis->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID))
|
---|
1198 | {
|
---|
1199 | PRTCRSPCINDIRECTDATACONTENT pIndData = pThis->pSignedData->ContentInfo.u.pIndirectDataContent;
|
---|
1200 | Assert(pIndData);
|
---|
1201 |
|
---|
1202 | /*
|
---|
1203 | * Check that things add up.
|
---|
1204 | */
|
---|
1205 | rc = RTCrPkcs7SignedData_CheckSanity(pThis->pSignedData,
|
---|
1206 | RTCRPKCS7SIGNEDDATA_SANITY_F_AUTHENTICODE
|
---|
1207 | | RTCRPKCS7SIGNEDDATA_SANITY_F_ONLY_KNOWN_HASH
|
---|
1208 | | RTCRPKCS7SIGNEDDATA_SANITY_F_SIGNING_CERT_PRESENT,
|
---|
1209 | RTErrInfoInitStatic(&ErrInfo), "SD");
|
---|
1210 | if (RT_SUCCESS(rc))
|
---|
1211 | {
|
---|
1212 | rc = RTCrSpcIndirectDataContent_CheckSanityEx(pIndData,
|
---|
1213 | pThis->pSignedData,
|
---|
1214 | RTCRSPCINDIRECTDATACONTENT_SANITY_F_ONLY_KNOWN_HASH,
|
---|
1215 | RTErrInfoInitStatic(&ErrInfo));
|
---|
1216 | if (RT_FAILURE(rc))
|
---|
1217 | RTMsgError("SPC indirect data content sanity check failed for '%s': %Rrc - %s\n",
|
---|
1218 | pThis->pszFilename, rc, ErrInfo.szMsg);
|
---|
1219 | }
|
---|
1220 | else
|
---|
1221 | RTMsgError("PKCS#7 sanity check failed for '%s': %Rrc - %s\n", pThis->pszFilename, rc, ErrInfo.szMsg);
|
---|
1222 | }
|
---|
1223 | else if (!strcmp(pThis->pSignedData->ContentInfo.ContentType.szObjId, RTCR_PKCS7_DATA_OID))
|
---|
1224 | { /* apple code signing */ }
|
---|
1225 | else if (!fCatalog)
|
---|
1226 | RTMsgError("Unexpected the signed content in '%s': %s (expected %s)", pThis->pszFilename,
|
---|
1227 | pThis->pSignedData->ContentInfo.ContentType.szObjId, RTCRSPCINDIRECTDATACONTENT_OID);
|
---|
1228 | }
|
---|
1229 | else
|
---|
1230 | rc = RTMsgErrorRc(VERR_CR_PKCS7_NOT_SIGNED_DATA,
|
---|
1231 | "PKCS#7 content is inside '%s' is not 'signedData': %s\n",
|
---|
1232 | pThis->pszFilename, pThis->ContentInfo.ContentType.szObjId);
|
---|
1233 | }
|
---|
1234 | else
|
---|
1235 | RTMsgError("RTCrPkcs7ContentInfo_DecodeAsn1 failed on '%s': %Rrc - %s\n", pThis->pszFilename, rc, ErrInfo.szMsg);
|
---|
1236 | return rc;
|
---|
1237 | }
|
---|
1238 |
|
---|
1239 |
|
---|
1240 | /**
|
---|
1241 | * Reads and decodes PKCS\#7 signature from the given cat file.
|
---|
1242 | *
|
---|
1243 | * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error message
|
---|
1244 | * on failure.
|
---|
1245 | * @param pThis The structure to initialize.
|
---|
1246 | * @param pszFilename The catalog (or any other DER PKCS\#7) filename.
|
---|
1247 | * @param cVerbosity The verbosity.
|
---|
1248 | */
|
---|
1249 | static RTEXITCODE SignToolPkcs7_InitFromFile(PSIGNTOOLPKCS7 pThis, const char *pszFilename, unsigned cVerbosity)
|
---|
1250 | {
|
---|
1251 | /*
|
---|
1252 | * Init the return structure.
|
---|
1253 | */
|
---|
1254 | RT_ZERO(*pThis);
|
---|
1255 | pThis->pszFilename = pszFilename;
|
---|
1256 | pThis->enmType = RTSIGNTOOLFILETYPE_CAT;
|
---|
1257 |
|
---|
1258 | /*
|
---|
1259 | * Lazy bird uses RTFileReadAll and duplicates the allocation.
|
---|
1260 | */
|
---|
1261 | void *pvFile;
|
---|
1262 | int rc = RTFileReadAll(pszFilename, &pvFile, &pThis->cbBuf);
|
---|
1263 | if (RT_SUCCESS(rc))
|
---|
1264 | {
|
---|
1265 | pThis->pbBuf = (uint8_t *)RTMemDup(pvFile, pThis->cbBuf);
|
---|
1266 | RTFileReadAllFree(pvFile, pThis->cbBuf);
|
---|
1267 | if (pThis->pbBuf)
|
---|
1268 | {
|
---|
1269 | if (cVerbosity > 2)
|
---|
1270 | RTPrintf("PKCS#7 signature: %u bytes\n", pThis->cbBuf);
|
---|
1271 |
|
---|
1272 | /*
|
---|
1273 | * Decode it.
|
---|
1274 | */
|
---|
1275 | rc = SignToolPkcs7_Decode(pThis, true /*fCatalog*/);
|
---|
1276 | if (RT_SUCCESS(rc))
|
---|
1277 | return RTEXITCODE_SUCCESS;
|
---|
1278 | }
|
---|
1279 | else
|
---|
1280 | RTMsgError("Out of memory!");
|
---|
1281 | }
|
---|
1282 | else
|
---|
1283 | RTMsgError("Error reading '%s' into memory: %Rrc", pszFilename, rc);
|
---|
1284 |
|
---|
1285 | SignToolPkcs7_Delete(pThis);
|
---|
1286 | return RTEXITCODE_FAILURE;
|
---|
1287 | }
|
---|
1288 |
|
---|
1289 |
|
---|
1290 | /**
|
---|
1291 | * Encodes the signature into the SIGNTOOLPKCS7::pbNewBuf and
|
---|
1292 | * SIGNTOOLPKCS7::cbNewBuf members.
|
---|
1293 | *
|
---|
1294 | * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error message
|
---|
1295 | * on failure.
|
---|
1296 | * @param pThis The signature to encode.
|
---|
1297 | * @param cVerbosity The verbosity.
|
---|
1298 | */
|
---|
1299 | static RTEXITCODE SignToolPkcs7_Encode(PSIGNTOOLPKCS7 pThis, unsigned cVerbosity)
|
---|
1300 | {
|
---|
1301 | RTERRINFOSTATIC StaticErrInfo;
|
---|
1302 | PRTASN1CORE pRoot = RTCrPkcs7ContentInfo_GetAsn1Core(&pThis->ContentInfo);
|
---|
1303 | uint32_t cbEncoded;
|
---|
1304 | int rc = RTAsn1EncodePrepare(pRoot, RTASN1ENCODE_F_DER, &cbEncoded, RTErrInfoInitStatic(&StaticErrInfo));
|
---|
1305 | if (RT_SUCCESS(rc))
|
---|
1306 | {
|
---|
1307 | if (cVerbosity >= 4)
|
---|
1308 | RTAsn1Dump(pRoot, 0, 0, RTStrmDumpPrintfV, g_pStdOut);
|
---|
1309 |
|
---|
1310 | RTMemFree(pThis->pbNewBuf);
|
---|
1311 | pThis->cbNewBuf = cbEncoded;
|
---|
1312 | pThis->pbNewBuf = (uint8_t *)RTMemAllocZ(cbEncoded);
|
---|
1313 | if (pThis->pbNewBuf)
|
---|
1314 | {
|
---|
1315 | rc = RTAsn1EncodeToBuffer(pRoot, RTASN1ENCODE_F_DER, pThis->pbNewBuf, pThis->cbNewBuf,
|
---|
1316 | RTErrInfoInitStatic(&StaticErrInfo));
|
---|
1317 | if (RT_SUCCESS(rc))
|
---|
1318 | {
|
---|
1319 | if (cVerbosity > 1)
|
---|
1320 | RTMsgInfo("Encoded signature to %u bytes", cbEncoded);
|
---|
1321 | return RTEXITCODE_SUCCESS;
|
---|
1322 | }
|
---|
1323 | RTMsgError("RTAsn1EncodeToBuffer failed: %Rrc", rc);
|
---|
1324 |
|
---|
1325 | RTMemFree(pThis->pbNewBuf);
|
---|
1326 | pThis->pbNewBuf = NULL;
|
---|
1327 | }
|
---|
1328 | else
|
---|
1329 | RTMsgError("Failed to allocate %u bytes!", cbEncoded);
|
---|
1330 | }
|
---|
1331 | else
|
---|
1332 | RTMsgError("RTAsn1EncodePrepare failed: %Rrc - %s", rc, StaticErrInfo.szMsg);
|
---|
1333 | return RTEXITCODE_FAILURE;
|
---|
1334 | }
|
---|
1335 |
|
---|
1336 |
|
---|
1337 | /**
|
---|
1338 | * Helper that makes sure the UnauthenticatedAttributes are present in the given
|
---|
1339 | * SignerInfo structure.
|
---|
1340 | *
|
---|
1341 | * Call this before trying to modify the array.
|
---|
1342 | *
|
---|
1343 | * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error already
|
---|
1344 | * displayed on failure.
|
---|
1345 | * @param pSignerInfo The SignerInfo structure in question.
|
---|
1346 | */
|
---|
1347 | static RTEXITCODE SignToolPkcs7_EnsureUnauthenticatedAttributesPresent(PRTCRPKCS7SIGNERINFO pSignerInfo)
|
---|
1348 | {
|
---|
1349 | if (pSignerInfo->UnauthenticatedAttributes.cItems == 0)
|
---|
1350 | {
|
---|
1351 | /* HACK ALERT! Invent ASN.1 setters/whatever for members to replace this mess. */
|
---|
1352 |
|
---|
1353 | if (pSignerInfo->AuthenticatedAttributes.cItems == 0)
|
---|
1354 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No authenticated or unauthenticated attributes! Sorry, no can do.");
|
---|
1355 |
|
---|
1356 | Assert(pSignerInfo->UnauthenticatedAttributes.SetCore.Asn1Core.uTag == 0);
|
---|
1357 | int rc = RTAsn1SetCore_Init(&pSignerInfo->UnauthenticatedAttributes.SetCore,
|
---|
1358 | pSignerInfo->AuthenticatedAttributes.SetCore.Asn1Core.pOps);
|
---|
1359 | if (RT_FAILURE(rc))
|
---|
1360 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTAsn1SetCore_Init failed: %Rrc", rc);
|
---|
1361 | pSignerInfo->UnauthenticatedAttributes.SetCore.Asn1Core.uTag = 1;
|
---|
1362 | pSignerInfo->UnauthenticatedAttributes.SetCore.Asn1Core.fClass = ASN1_TAGCLASS_CONTEXT | ASN1_TAGFLAG_CONSTRUCTED;
|
---|
1363 | RTAsn1MemInitArrayAllocation(&pSignerInfo->UnauthenticatedAttributes.Allocation,
|
---|
1364 | pSignerInfo->AuthenticatedAttributes.Allocation.pAllocator,
|
---|
1365 | sizeof(**pSignerInfo->UnauthenticatedAttributes.papItems));
|
---|
1366 | }
|
---|
1367 | return RTEXITCODE_SUCCESS;
|
---|
1368 | }
|
---|
1369 |
|
---|
1370 |
|
---|
1371 | /**
|
---|
1372 | * Adds the @a pSrc signature as a nested signature.
|
---|
1373 | *
|
---|
1374 | * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error message
|
---|
1375 | * on failure.
|
---|
1376 | * @param pThis The signature to modify.
|
---|
1377 | * @param pSrc The signature to add as nested.
|
---|
1378 | * @param cVerbosity The verbosity.
|
---|
1379 | * @param fPrepend Whether to prepend (true) or append (false) the
|
---|
1380 | * source signature to the nested attribute.
|
---|
1381 | */
|
---|
1382 | static RTEXITCODE SignToolPkcs7_AddNestedSignature(PSIGNTOOLPKCS7 pThis, PSIGNTOOLPKCS7 pSrc,
|
---|
1383 | unsigned cVerbosity, bool fPrepend)
|
---|
1384 | {
|
---|
1385 | PRTCRPKCS7SIGNERINFO pSignerInfo = pThis->pSignedData->SignerInfos.papItems[0];
|
---|
1386 |
|
---|
1387 | /*
|
---|
1388 | * Deal with UnauthenticatedAttributes being absent before trying to append to the array.
|
---|
1389 | */
|
---|
1390 | RTEXITCODE rcExit = SignToolPkcs7_EnsureUnauthenticatedAttributesPresent(pSignerInfo);
|
---|
1391 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
1392 | return rcExit;
|
---|
1393 |
|
---|
1394 | /*
|
---|
1395 | * Find or add an unauthenticated attribute for nested signatures.
|
---|
1396 | */
|
---|
1397 | int rc = VERR_NOT_FOUND;
|
---|
1398 | PRTCRPKCS7ATTRIBUTE pAttr = NULL;
|
---|
1399 | int32_t iPos = pSignerInfo->UnauthenticatedAttributes.cItems;
|
---|
1400 | while (iPos-- > 0)
|
---|
1401 | if (pSignerInfo->UnauthenticatedAttributes.papItems[iPos]->enmType == RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE)
|
---|
1402 | {
|
---|
1403 | pAttr = pSignerInfo->UnauthenticatedAttributes.papItems[iPos];
|
---|
1404 | rc = VINF_SUCCESS;
|
---|
1405 | break;
|
---|
1406 | }
|
---|
1407 | if (iPos < 0)
|
---|
1408 | {
|
---|
1409 | iPos = RTCrPkcs7Attributes_Append(&pSignerInfo->UnauthenticatedAttributes);
|
---|
1410 | if (iPos >= 0)
|
---|
1411 | {
|
---|
1412 | if (cVerbosity >= 3)
|
---|
1413 | RTMsgInfo("Adding UnauthenticatedAttribute #%u...", iPos);
|
---|
1414 | Assert((uint32_t)iPos < pSignerInfo->UnauthenticatedAttributes.cItems);
|
---|
1415 |
|
---|
1416 | pAttr = pSignerInfo->UnauthenticatedAttributes.papItems[iPos];
|
---|
1417 | rc = RTAsn1ObjId_InitFromString(&pAttr->Type, RTCR_PKCS9_ID_MS_NESTED_SIGNATURE, pAttr->Allocation.pAllocator);
|
---|
1418 | if (RT_SUCCESS(rc))
|
---|
1419 | {
|
---|
1420 | /** @todo Generalize the Type + enmType DYN stuff and generate setters. */
|
---|
1421 | Assert(pAttr->enmType == RTCRPKCS7ATTRIBUTETYPE_NOT_PRESENT);
|
---|
1422 | Assert(pAttr->uValues.pContentInfos == NULL);
|
---|
1423 | pAttr->enmType = RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE;
|
---|
1424 | rc = RTAsn1MemAllocZ(&pAttr->Allocation, (void **)&pAttr->uValues.pContentInfos,
|
---|
1425 | sizeof(*pAttr->uValues.pContentInfos));
|
---|
1426 | if (RT_SUCCESS(rc))
|
---|
1427 | {
|
---|
1428 | rc = RTCrPkcs7SetOfContentInfos_Init(pAttr->uValues.pContentInfos, pAttr->Allocation.pAllocator);
|
---|
1429 | if (!RT_SUCCESS(rc))
|
---|
1430 | RTMsgError("RTCrPkcs7ContentInfos_Init failed: %Rrc", rc);
|
---|
1431 | }
|
---|
1432 | else
|
---|
1433 | RTMsgError("RTAsn1MemAllocZ failed: %Rrc", rc);
|
---|
1434 | }
|
---|
1435 | else
|
---|
1436 | RTMsgError("RTAsn1ObjId_InitFromString failed: %Rrc", rc);
|
---|
1437 | }
|
---|
1438 | else
|
---|
1439 | RTMsgError("RTCrPkcs7Attributes_Append failed: %Rrc", iPos);
|
---|
1440 | }
|
---|
1441 | else if (cVerbosity >= 2)
|
---|
1442 | RTMsgInfo("Found UnauthenticatedAttribute #%u...", iPos);
|
---|
1443 | if (RT_SUCCESS(rc))
|
---|
1444 | {
|
---|
1445 | /*
|
---|
1446 | * Append/prepend the signature.
|
---|
1447 | */
|
---|
1448 | uint32_t iActualPos = UINT32_MAX;
|
---|
1449 | iPos = fPrepend ? 0 : pAttr->uValues.pContentInfos->cItems;
|
---|
1450 | rc = RTCrPkcs7SetOfContentInfos_InsertEx(pAttr->uValues.pContentInfos, iPos, &pSrc->ContentInfo,
|
---|
1451 | pAttr->Allocation.pAllocator, &iActualPos);
|
---|
1452 | if (RT_SUCCESS(rc))
|
---|
1453 | {
|
---|
1454 | if (cVerbosity > 0)
|
---|
1455 | RTMsgInfo("Added nested signature (#%u)", iActualPos);
|
---|
1456 | if (cVerbosity >= 3)
|
---|
1457 | {
|
---|
1458 | RTMsgInfo("SingerInfo dump after change:");
|
---|
1459 | RTAsn1Dump(RTCrPkcs7SignerInfo_GetAsn1Core(pSignerInfo), 0, 2, RTStrmDumpPrintfV, g_pStdOut);
|
---|
1460 | }
|
---|
1461 | return RTEXITCODE_SUCCESS;
|
---|
1462 | }
|
---|
1463 |
|
---|
1464 | RTMsgError("RTCrPkcs7ContentInfos_InsertEx failed: %Rrc", rc);
|
---|
1465 | }
|
---|
1466 | return RTEXITCODE_FAILURE;
|
---|
1467 | }
|
---|
1468 |
|
---|
1469 |
|
---|
1470 | /**
|
---|
1471 | * Writes the signature to the file.
|
---|
1472 | *
|
---|
1473 | * Caller must have called SignToolPkcs7_Encode() prior to this function.
|
---|
1474 | *
|
---|
1475 | * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error
|
---|
1476 | * message on failure.
|
---|
1477 | * @param pThis The file which to write.
|
---|
1478 | * @param cVerbosity The verbosity.
|
---|
1479 | */
|
---|
1480 | static RTEXITCODE SignToolPkcs7_WriteSignatureToFile(PSIGNTOOLPKCS7 pThis, const char *pszFilename, unsigned cVerbosity)
|
---|
1481 | {
|
---|
1482 | AssertReturn(pThis->cbNewBuf && pThis->pbNewBuf, RTEXITCODE_FAILURE);
|
---|
1483 |
|
---|
1484 | /*
|
---|
1485 | * Open+truncate file, write new signature, close. Simple.
|
---|
1486 | */
|
---|
1487 | RTFILE hFile;
|
---|
1488 | int rc = RTFileOpen(&hFile, pszFilename, RTFILE_O_WRITE | RTFILE_O_OPEN_CREATE | RTFILE_O_TRUNCATE | RTFILE_O_DENY_WRITE);
|
---|
1489 | if (RT_SUCCESS(rc))
|
---|
1490 | {
|
---|
1491 | rc = RTFileWrite(hFile, pThis->pbNewBuf, pThis->cbNewBuf, NULL);
|
---|
1492 | if (RT_SUCCESS(rc))
|
---|
1493 | {
|
---|
1494 | rc = RTFileClose(hFile);
|
---|
1495 | if (RT_SUCCESS(rc))
|
---|
1496 | {
|
---|
1497 | if (cVerbosity > 0)
|
---|
1498 | RTMsgInfo("Wrote %u bytes to %s", pThis->cbNewBuf, pszFilename);
|
---|
1499 | return RTEXITCODE_SUCCESS;
|
---|
1500 | }
|
---|
1501 |
|
---|
1502 | RTMsgError("RTFileClose failed on %s: %Rrc", pszFilename, rc);
|
---|
1503 | }
|
---|
1504 | else
|
---|
1505 | RTMsgError("Write error on %s: %Rrc", pszFilename, rc);
|
---|
1506 | }
|
---|
1507 | else
|
---|
1508 | RTMsgError("Failed to open %s for writing: %Rrc", pszFilename, rc);
|
---|
1509 | return RTEXITCODE_FAILURE;
|
---|
1510 | }
|
---|
1511 |
|
---|
1512 |
|
---|
1513 |
|
---|
1514 | /**
|
---|
1515 | * Worker for recursively searching for MS nested signatures and signer infos.
|
---|
1516 | *
|
---|
1517 | * @returns Pointer to the signer info corresponding to @a iReqSignature. NULL
|
---|
1518 | * if not found.
|
---|
1519 | * @param pSignedData The signature to search.
|
---|
1520 | * @param piNextSignature Pointer to the variable keeping track of the next
|
---|
1521 | * signature number.
|
---|
1522 | * @param iReqSignature The request signature number.
|
---|
1523 | * @param ppSignedData Where to return the signature data structure.
|
---|
1524 | * Optional.
|
---|
1525 | */
|
---|
1526 | static PRTCRPKCS7SIGNERINFO SignToolPkcs7_FindNestedSignatureByIndexWorker(PRTCRPKCS7SIGNEDDATA pSignedData,
|
---|
1527 | uint32_t *piNextSignature,
|
---|
1528 | uint32_t iReqSignature,
|
---|
1529 | PRTCRPKCS7SIGNEDDATA *ppSignedData)
|
---|
1530 | {
|
---|
1531 | for (uint32_t iSignerInfo = 0; iSignerInfo < pSignedData->SignerInfos.cItems; iSignerInfo++)
|
---|
1532 | {
|
---|
1533 | /* Match?*/
|
---|
1534 | PRTCRPKCS7SIGNERINFO pSignerInfo = pSignedData->SignerInfos.papItems[iSignerInfo];
|
---|
1535 | if (*piNextSignature == iReqSignature)
|
---|
1536 | {
|
---|
1537 | if (ppSignedData)
|
---|
1538 | *ppSignedData = pSignedData;
|
---|
1539 | return pSignerInfo;
|
---|
1540 | }
|
---|
1541 | *piNextSignature += 1;
|
---|
1542 |
|
---|
1543 | /* Look for nested signatures. */
|
---|
1544 | for (uint32_t iAttrib = 0; iAttrib < pSignerInfo->UnauthenticatedAttributes.cItems; iAttrib++)
|
---|
1545 | if (pSignerInfo->UnauthenticatedAttributes.papItems[iAttrib]->enmType == RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE)
|
---|
1546 | {
|
---|
1547 | PRTCRPKCS7SETOFCONTENTINFOS pCntInfos;
|
---|
1548 | pCntInfos = pSignerInfo->UnauthenticatedAttributes.papItems[iAttrib]->uValues.pContentInfos;
|
---|
1549 | for (uint32_t iCntInfo = 0; iCntInfo < pCntInfos->cItems; iCntInfo++)
|
---|
1550 | {
|
---|
1551 | PRTCRPKCS7CONTENTINFO pCntInfo = pCntInfos->papItems[iCntInfo];
|
---|
1552 | if (RTCrPkcs7ContentInfo_IsSignedData(pCntInfo))
|
---|
1553 | {
|
---|
1554 | PRTCRPKCS7SIGNERINFO pRet;
|
---|
1555 | pRet = SignToolPkcs7_FindNestedSignatureByIndexWorker(pCntInfo->u.pSignedData, piNextSignature,
|
---|
1556 | iReqSignature, ppSignedData);
|
---|
1557 | if (pRet)
|
---|
1558 | return pRet;
|
---|
1559 | }
|
---|
1560 | }
|
---|
1561 | }
|
---|
1562 | }
|
---|
1563 | return NULL;
|
---|
1564 | }
|
---|
1565 |
|
---|
1566 |
|
---|
1567 | /**
|
---|
1568 | * Locates the given nested signature.
|
---|
1569 | *
|
---|
1570 | * @returns Pointer to the signer info corresponding to @a iReqSignature. NULL
|
---|
1571 | * if not found.
|
---|
1572 | * @param pThis The PKCS\#7 structure to search.
|
---|
1573 | * @param iReqSignature The requested signature number.
|
---|
1574 | * @param ppSignedData Where to return the pointer to the signed data that
|
---|
1575 | * the returned signer info belongs to.
|
---|
1576 | *
|
---|
1577 | * @todo Move into SPC or PKCS\#7.
|
---|
1578 | */
|
---|
1579 | static PRTCRPKCS7SIGNERINFO SignToolPkcs7_FindNestedSignatureByIndex(PSIGNTOOLPKCS7 pThis, uint32_t iReqSignature,
|
---|
1580 | PRTCRPKCS7SIGNEDDATA *ppSignedData)
|
---|
1581 | {
|
---|
1582 | uint32_t iNextSignature = 0;
|
---|
1583 | return SignToolPkcs7_FindNestedSignatureByIndexWorker(pThis->pSignedData, &iNextSignature, iReqSignature, ppSignedData);
|
---|
1584 | }
|
---|
1585 |
|
---|
1586 |
|
---|
1587 | /**
|
---|
1588 | * Count the number of signatures, nested or otherwise.
|
---|
1589 | *
|
---|
1590 | * @returns Number of signatures.
|
---|
1591 | * @param pThis The PKCS\#7 structure to search.
|
---|
1592 | *
|
---|
1593 | * @todo Move into SPC or PKCS\#7.
|
---|
1594 | */
|
---|
1595 | static uint32_t SignToolPkcs7_CountSignatures(PSIGNTOOLPKCS7 pThis)
|
---|
1596 | {
|
---|
1597 | uint32_t iNextSignature = 0;
|
---|
1598 | PRTCRPKCS7SIGNEDDATA pSignedData = NULL;
|
---|
1599 | SignToolPkcs7_FindNestedSignatureByIndexWorker(pThis->pSignedData, &iNextSignature, UINT32_MAX / 2, &pSignedData);
|
---|
1600 | return iNextSignature;
|
---|
1601 | }
|
---|
1602 |
|
---|
1603 |
|
---|
1604 | /**
|
---|
1605 | * Reads and decodes PKCS\#7 signature from the given executable, if it has one.
|
---|
1606 | *
|
---|
1607 | * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error message
|
---|
1608 | * on failure.
|
---|
1609 | * @param pThis The structure to initialize.
|
---|
1610 | * @param pszFilename The executable filename.
|
---|
1611 | * @param cVerbosity The verbosity.
|
---|
1612 | * @param enmLdrArch For FAT binaries.
|
---|
1613 | * @param fAllowUnsigned Whether to allow unsigned binaries.
|
---|
1614 | */
|
---|
1615 | static RTEXITCODE SignToolPkcs7Exe_InitFromFile(PSIGNTOOLPKCS7EXE pThis, const char *pszFilename, unsigned cVerbosity,
|
---|
1616 | RTLDRARCH enmLdrArch = RTLDRARCH_WHATEVER, bool fAllowUnsigned = false)
|
---|
1617 | {
|
---|
1618 | /*
|
---|
1619 | * Init the return structure.
|
---|
1620 | */
|
---|
1621 | RT_ZERO(*pThis);
|
---|
1622 | pThis->hLdrMod = NIL_RTLDRMOD;
|
---|
1623 | pThis->pszFilename = pszFilename;
|
---|
1624 | pThis->enmType = RTSIGNTOOLFILETYPE_EXE;
|
---|
1625 |
|
---|
1626 | /*
|
---|
1627 | * Open the image and check if it's signed.
|
---|
1628 | */
|
---|
1629 | int rc = RTLdrOpen(pszFilename, RTLDR_O_FOR_VALIDATION, enmLdrArch, &pThis->hLdrMod);
|
---|
1630 | if (RT_SUCCESS(rc))
|
---|
1631 | {
|
---|
1632 | bool fIsSigned = false;
|
---|
1633 | rc = RTLdrQueryProp(pThis->hLdrMod, RTLDRPROP_IS_SIGNED, &fIsSigned, sizeof(fIsSigned));
|
---|
1634 | if (RT_SUCCESS(rc) && fIsSigned)
|
---|
1635 | {
|
---|
1636 | /*
|
---|
1637 | * Query the PKCS#7 data (assuming M$ style signing) and hand it to a worker.
|
---|
1638 | */
|
---|
1639 | size_t cbActual = 0;
|
---|
1640 | #ifdef DEBUG
|
---|
1641 | size_t cbBuf = 64;
|
---|
1642 | #else
|
---|
1643 | size_t cbBuf = _512K;
|
---|
1644 | #endif
|
---|
1645 | void *pvBuf = RTMemAllocZ(cbBuf);
|
---|
1646 | if (pvBuf)
|
---|
1647 | {
|
---|
1648 | rc = RTLdrQueryPropEx(pThis->hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/, pvBuf, cbBuf, &cbActual);
|
---|
1649 | if (rc == VERR_BUFFER_OVERFLOW)
|
---|
1650 | {
|
---|
1651 | RTMemFree(pvBuf);
|
---|
1652 | cbBuf = cbActual;
|
---|
1653 | pvBuf = RTMemAllocZ(cbActual);
|
---|
1654 | if (pvBuf)
|
---|
1655 | rc = RTLdrQueryPropEx(pThis->hLdrMod, RTLDRPROP_PKCS7_SIGNED_DATA, NULL /*pvBits*/,
|
---|
1656 | pvBuf, cbBuf, &cbActual);
|
---|
1657 | else
|
---|
1658 | rc = VERR_NO_MEMORY;
|
---|
1659 | }
|
---|
1660 | }
|
---|
1661 | else
|
---|
1662 | rc = VERR_NO_MEMORY;
|
---|
1663 |
|
---|
1664 | pThis->pbBuf = (uint8_t *)pvBuf;
|
---|
1665 | pThis->cbBuf = cbActual;
|
---|
1666 | if (RT_SUCCESS(rc))
|
---|
1667 | {
|
---|
1668 | if (cVerbosity > 2)
|
---|
1669 | RTPrintf("PKCS#7 signature: %u bytes\n", cbActual);
|
---|
1670 | if (cVerbosity > 3)
|
---|
1671 | RTPrintf("%.*Rhxd\n", cbActual, pvBuf);
|
---|
1672 |
|
---|
1673 | /*
|
---|
1674 | * Decode it.
|
---|
1675 | */
|
---|
1676 | rc = SignToolPkcs7_Decode(pThis, false /*fCatalog*/);
|
---|
1677 | if (RT_SUCCESS(rc))
|
---|
1678 | return RTEXITCODE_SUCCESS;
|
---|
1679 | }
|
---|
1680 | else
|
---|
1681 | RTMsgError("RTLdrQueryPropEx/RTLDRPROP_PKCS7_SIGNED_DATA failed on '%s': %Rrc\n", pszFilename, rc);
|
---|
1682 | }
|
---|
1683 | else if (RT_SUCCESS(rc))
|
---|
1684 | {
|
---|
1685 | if (!fAllowUnsigned || cVerbosity >= 2)
|
---|
1686 | RTMsgInfo("'%s': not signed\n", pszFilename);
|
---|
1687 | if (fAllowUnsigned)
|
---|
1688 | return RTEXITCODE_SUCCESS;
|
---|
1689 | }
|
---|
1690 | else
|
---|
1691 | RTMsgError("RTLdrQueryProp/RTLDRPROP_IS_SIGNED failed on '%s': %Rrc\n", pszFilename, rc);
|
---|
1692 | }
|
---|
1693 | else
|
---|
1694 | RTMsgError("Error opening executable image '%s': %Rrc", pszFilename, rc);
|
---|
1695 |
|
---|
1696 | SignToolPkcs7Exe_Delete(pThis);
|
---|
1697 | return RTEXITCODE_FAILURE;
|
---|
1698 | }
|
---|
1699 |
|
---|
1700 |
|
---|
1701 | /**
|
---|
1702 | * Calculates the checksum of an executable.
|
---|
1703 | *
|
---|
1704 | * @returns Success indicator (errors are reported)
|
---|
1705 | * @param pThis The exe file to checksum.
|
---|
1706 | * @param hFile The file handle.
|
---|
1707 | * @param puCheckSum Where to return the checksum.
|
---|
1708 | */
|
---|
1709 | static bool SignToolPkcs7Exe_CalcPeCheckSum(PSIGNTOOLPKCS7EXE pThis, RTFILE hFile, uint32_t *puCheckSum)
|
---|
1710 | {
|
---|
1711 | #ifdef RT_OS_WINDOWS
|
---|
1712 | /*
|
---|
1713 | * Try use IMAGEHLP!MapFileAndCheckSumW first.
|
---|
1714 | */
|
---|
1715 | PRTUTF16 pwszPath;
|
---|
1716 | int rc = RTStrToUtf16(pThis->pszFilename, &pwszPath);
|
---|
1717 | if (RT_SUCCESS(rc))
|
---|
1718 | {
|
---|
1719 | decltype(MapFileAndCheckSumW) *pfnMapFileAndCheckSumW;
|
---|
1720 | pfnMapFileAndCheckSumW = (decltype(MapFileAndCheckSumW) *)RTLdrGetSystemSymbol("IMAGEHLP.DLL", "MapFileAndCheckSumW");
|
---|
1721 | if (pfnMapFileAndCheckSumW)
|
---|
1722 | {
|
---|
1723 | DWORD uOldSum = UINT32_MAX;
|
---|
1724 | DWORD uCheckSum = UINT32_MAX;
|
---|
1725 | DWORD dwRc = pfnMapFileAndCheckSumW(pwszPath, &uOldSum, &uCheckSum);
|
---|
1726 | if (dwRc == CHECKSUM_SUCCESS)
|
---|
1727 | {
|
---|
1728 | *puCheckSum = uCheckSum;
|
---|
1729 | return true;
|
---|
1730 | }
|
---|
1731 | }
|
---|
1732 | }
|
---|
1733 | #endif
|
---|
1734 |
|
---|
1735 | RT_NOREF(pThis, hFile, puCheckSum);
|
---|
1736 | RTMsgError("Implement check sum calcuation fallback!");
|
---|
1737 | return false;
|
---|
1738 | }
|
---|
1739 |
|
---|
1740 |
|
---|
1741 | /**
|
---|
1742 | * Writes the signature to the file.
|
---|
1743 | *
|
---|
1744 | * This has the side-effect of closing the hLdrMod member. So, it can only be
|
---|
1745 | * called once!
|
---|
1746 | *
|
---|
1747 | * Caller must have called SignToolPkcs7_Encode() prior to this function.
|
---|
1748 | *
|
---|
1749 | * @returns RTEXITCODE_SUCCESS on success, RTEXITCODE_FAILURE with error
|
---|
1750 | * message on failure.
|
---|
1751 | * @param pThis The file which to write.
|
---|
1752 | * @param cVerbosity The verbosity.
|
---|
1753 | */
|
---|
1754 | static RTEXITCODE SignToolPkcs7Exe_WriteSignatureToFile(PSIGNTOOLPKCS7EXE pThis, unsigned cVerbosity)
|
---|
1755 | {
|
---|
1756 | AssertReturn(pThis->cbNewBuf && pThis->pbNewBuf, RTEXITCODE_FAILURE);
|
---|
1757 |
|
---|
1758 | /*
|
---|
1759 | * Get the file header offset and arch before closing the destination handle.
|
---|
1760 | */
|
---|
1761 | uint32_t offNtHdrs;
|
---|
1762 | int rc = RTLdrQueryProp(pThis->hLdrMod, RTLDRPROP_FILE_OFF_HEADER, &offNtHdrs, sizeof(offNtHdrs));
|
---|
1763 | if (RT_SUCCESS(rc))
|
---|
1764 | {
|
---|
1765 | RTLDRARCH enmLdrArch = RTLdrGetArch(pThis->hLdrMod);
|
---|
1766 | if (enmLdrArch != RTLDRARCH_INVALID)
|
---|
1767 | {
|
---|
1768 | RTLdrClose(pThis->hLdrMod);
|
---|
1769 | pThis->hLdrMod = NIL_RTLDRMOD;
|
---|
1770 | unsigned cbNtHdrs = 0;
|
---|
1771 | switch (enmLdrArch)
|
---|
1772 | {
|
---|
1773 | case RTLDRARCH_AMD64:
|
---|
1774 | cbNtHdrs = sizeof(IMAGE_NT_HEADERS64);
|
---|
1775 | break;
|
---|
1776 | case RTLDRARCH_X86_32:
|
---|
1777 | cbNtHdrs = sizeof(IMAGE_NT_HEADERS32);
|
---|
1778 | break;
|
---|
1779 | default:
|
---|
1780 | RTMsgError("Unknown image arch: %d", enmLdrArch);
|
---|
1781 | }
|
---|
1782 | if (cbNtHdrs > 0)
|
---|
1783 | {
|
---|
1784 | if (cVerbosity > 0)
|
---|
1785 | RTMsgInfo("offNtHdrs=%#x cbNtHdrs=%u\n", offNtHdrs, cbNtHdrs);
|
---|
1786 |
|
---|
1787 | /*
|
---|
1788 | * Open the executable file for writing.
|
---|
1789 | */
|
---|
1790 | RTFILE hFile;
|
---|
1791 | rc = RTFileOpen(&hFile, pThis->pszFilename, RTFILE_O_READWRITE | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
|
---|
1792 | if (RT_SUCCESS(rc))
|
---|
1793 | {
|
---|
1794 | /* Read the file header and locate the security directory entry. */
|
---|
1795 | union
|
---|
1796 | {
|
---|
1797 | IMAGE_NT_HEADERS32 NtHdrs32;
|
---|
1798 | IMAGE_NT_HEADERS64 NtHdrs64;
|
---|
1799 | } uBuf;
|
---|
1800 | PIMAGE_DATA_DIRECTORY pSecDir = cbNtHdrs == sizeof(IMAGE_NT_HEADERS64)
|
---|
1801 | ? &uBuf.NtHdrs64.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY]
|
---|
1802 | : &uBuf.NtHdrs32.OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_SECURITY];
|
---|
1803 |
|
---|
1804 | rc = RTFileReadAt(hFile, offNtHdrs, &uBuf, cbNtHdrs, NULL);
|
---|
1805 | if ( RT_SUCCESS(rc)
|
---|
1806 | && uBuf.NtHdrs32.Signature == IMAGE_NT_SIGNATURE)
|
---|
1807 | {
|
---|
1808 | /*
|
---|
1809 | * Drop any old signature by truncating the file.
|
---|
1810 | */
|
---|
1811 | if ( pSecDir->Size > 8
|
---|
1812 | && pSecDir->VirtualAddress > offNtHdrs + sizeof(IMAGE_NT_HEADERS32))
|
---|
1813 | {
|
---|
1814 | rc = RTFileSetSize(hFile, pSecDir->VirtualAddress);
|
---|
1815 | if (RT_FAILURE(rc))
|
---|
1816 | RTMsgError("Error truncating file to %#x bytes: %Rrc", pSecDir->VirtualAddress, rc);
|
---|
1817 | }
|
---|
1818 | else if (pSecDir->Size != 0 && pSecDir->VirtualAddress == 0)
|
---|
1819 | rc = RTMsgErrorRc(VERR_BAD_EXE_FORMAT, "Bad security directory entry: VA=%#x Size=%#x",
|
---|
1820 | pSecDir->VirtualAddress, pSecDir->Size);
|
---|
1821 | if (RT_SUCCESS(rc))
|
---|
1822 | {
|
---|
1823 | /*
|
---|
1824 | * Pad the file with zero up to a WIN_CERTIFICATE_ALIGNMENT boundary.
|
---|
1825 | *
|
---|
1826 | * Since the hash algorithm hashes everything up to the signature data,
|
---|
1827 | * zero padding included, the alignment we do here must match the alignment
|
---|
1828 | * padding that done while calculating the hash.
|
---|
1829 | */
|
---|
1830 | uint32_t const cbWinCert = RT_UOFFSETOF(WIN_CERTIFICATE, bCertificate);
|
---|
1831 | uint64_t offCur = 0;
|
---|
1832 | rc = RTFileQuerySize(hFile, &offCur);
|
---|
1833 | if ( RT_SUCCESS(rc)
|
---|
1834 | && offCur < _2G)
|
---|
1835 | {
|
---|
1836 | if (offCur != RT_ALIGN_64(offCur, WIN_CERTIFICATE_ALIGNMENT))
|
---|
1837 | {
|
---|
1838 | uint32_t const cbNeeded = (uint32_t)(RT_ALIGN_64(offCur, WIN_CERTIFICATE_ALIGNMENT) - offCur);
|
---|
1839 | rc = RTFileWriteAt(hFile, offCur, g_abRTZero4K, cbNeeded, NULL);
|
---|
1840 | if (RT_SUCCESS(rc))
|
---|
1841 | offCur += cbNeeded;
|
---|
1842 | }
|
---|
1843 | if (RT_SUCCESS(rc))
|
---|
1844 | {
|
---|
1845 | /*
|
---|
1846 | * Write the header followed by the signature data.
|
---|
1847 | */
|
---|
1848 | uint32_t const cbZeroPad = (uint32_t)(RT_ALIGN_Z(pThis->cbNewBuf, 8) - pThis->cbNewBuf);
|
---|
1849 | pSecDir->VirtualAddress = (uint32_t)offCur;
|
---|
1850 | pSecDir->Size = cbWinCert + (uint32_t)pThis->cbNewBuf + cbZeroPad;
|
---|
1851 | if (cVerbosity >= 2)
|
---|
1852 | RTMsgInfo("Writing %u (%#x) bytes of signature at %#x (%u).\n",
|
---|
1853 | pSecDir->Size, pSecDir->Size, pSecDir->VirtualAddress, pSecDir->VirtualAddress);
|
---|
1854 |
|
---|
1855 | WIN_CERTIFICATE WinCert;
|
---|
1856 | WinCert.dwLength = pSecDir->Size;
|
---|
1857 | WinCert.wRevision = WIN_CERT_REVISION_2_0;
|
---|
1858 | WinCert.wCertificateType = WIN_CERT_TYPE_PKCS_SIGNED_DATA;
|
---|
1859 |
|
---|
1860 | rc = RTFileWriteAt(hFile, offCur, &WinCert, cbWinCert, NULL);
|
---|
1861 | if (RT_SUCCESS(rc))
|
---|
1862 | {
|
---|
1863 | offCur += cbWinCert;
|
---|
1864 | rc = RTFileWriteAt(hFile, offCur, pThis->pbNewBuf, pThis->cbNewBuf, NULL);
|
---|
1865 | }
|
---|
1866 | if (RT_SUCCESS(rc) && cbZeroPad)
|
---|
1867 | {
|
---|
1868 | offCur += pThis->cbNewBuf;
|
---|
1869 | rc = RTFileWriteAt(hFile, offCur, g_abRTZero4K, cbZeroPad, NULL);
|
---|
1870 | }
|
---|
1871 | if (RT_SUCCESS(rc))
|
---|
1872 | {
|
---|
1873 | /*
|
---|
1874 | * Reset the checksum (sec dir updated already) and rewrite the header.
|
---|
1875 | */
|
---|
1876 | uBuf.NtHdrs32.OptionalHeader.CheckSum = 0;
|
---|
1877 | offCur = offNtHdrs;
|
---|
1878 | rc = RTFileWriteAt(hFile, offNtHdrs, &uBuf, cbNtHdrs, NULL);
|
---|
1879 | if (RT_SUCCESS(rc))
|
---|
1880 | rc = RTFileFlush(hFile);
|
---|
1881 | if (RT_SUCCESS(rc))
|
---|
1882 | {
|
---|
1883 | /*
|
---|
1884 | * Calc checksum and write out the header again.
|
---|
1885 | */
|
---|
1886 | uint32_t uCheckSum = UINT32_MAX;
|
---|
1887 | if (SignToolPkcs7Exe_CalcPeCheckSum(pThis, hFile, &uCheckSum))
|
---|
1888 | {
|
---|
1889 | uBuf.NtHdrs32.OptionalHeader.CheckSum = uCheckSum;
|
---|
1890 | rc = RTFileWriteAt(hFile, offNtHdrs, &uBuf, cbNtHdrs, NULL);
|
---|
1891 | if (RT_SUCCESS(rc))
|
---|
1892 | rc = RTFileFlush(hFile);
|
---|
1893 | if (RT_SUCCESS(rc))
|
---|
1894 | {
|
---|
1895 | rc = RTFileClose(hFile);
|
---|
1896 | if (RT_SUCCESS(rc))
|
---|
1897 | return RTEXITCODE_SUCCESS;
|
---|
1898 | RTMsgError("RTFileClose failed: %Rrc\n", rc);
|
---|
1899 | return RTEXITCODE_FAILURE;
|
---|
1900 | }
|
---|
1901 | }
|
---|
1902 | }
|
---|
1903 | }
|
---|
1904 | }
|
---|
1905 | if (RT_FAILURE(rc))
|
---|
1906 | RTMsgError("Write error at %#RX64: %Rrc", offCur, rc);
|
---|
1907 | }
|
---|
1908 | else if (RT_SUCCESS(rc))
|
---|
1909 | RTMsgError("File to big: %'RU64 bytes", offCur);
|
---|
1910 | else
|
---|
1911 | RTMsgError("RTFileQuerySize failed: %Rrc", rc);
|
---|
1912 | }
|
---|
1913 | }
|
---|
1914 | else if (RT_SUCCESS(rc))
|
---|
1915 | RTMsgError("Not NT executable header!");
|
---|
1916 | else
|
---|
1917 | RTMsgError("Error reading NT headers (%#x bytes) at %#x: %Rrc", cbNtHdrs, offNtHdrs, rc);
|
---|
1918 | RTFileClose(hFile);
|
---|
1919 | }
|
---|
1920 | else
|
---|
1921 | RTMsgError("Failed to open '%s' for writing: %Rrc", pThis->pszFilename, rc);
|
---|
1922 | }
|
---|
1923 | }
|
---|
1924 | else
|
---|
1925 | RTMsgError("RTLdrGetArch failed!");
|
---|
1926 | }
|
---|
1927 | else
|
---|
1928 | RTMsgError("RTLdrQueryProp/RTLDRPROP_FILE_OFF_HEADER failed: %Rrc", rc);
|
---|
1929 | return RTEXITCODE_FAILURE;
|
---|
1930 | }
|
---|
1931 |
|
---|
1932 | #ifndef IPRT_SIGNTOOL_NO_SIGNING
|
---|
1933 |
|
---|
1934 | static PRTCRPKCS7ATTRIBUTE SignToolPkcs7_AuthAttribAppend(PRTCRPKCS7ATTRIBUTES pAuthAttribs)
|
---|
1935 | {
|
---|
1936 | int32_t iPos = RTCrPkcs7Attributes_Append(pAuthAttribs);
|
---|
1937 | if (iPos >= 0)
|
---|
1938 | return pAuthAttribs->papItems[iPos];
|
---|
1939 | RTMsgError("RTCrPkcs7Attributes_Append failed: %Rrc", iPos);
|
---|
1940 | return NULL;
|
---|
1941 | }
|
---|
1942 |
|
---|
1943 |
|
---|
1944 | static RTEXITCODE SignToolPkcs7_AuthAttribsAddSigningTime(PRTCRPKCS7ATTRIBUTES pAuthAttribs, RTTIMESPEC SigningTime)
|
---|
1945 | {
|
---|
1946 | /*
|
---|
1947 | * Signing time. For the old-style timestamps, Symantec used ASN.1 UTC TIME.
|
---|
1948 | * start -vv vv=ASN1_TAG_UTC_TIME
|
---|
1949 | * 00000187d6a65fd0/23b0: 0d 01 09 05 31 0f 17 0d-31 36 31 30 30 35 30 37 ....1...16100507
|
---|
1950 | * 00000187d6a65fe0/23c0: 35 30 33 30 5a 30 23 06-09 2a 86 48 86 f7 0d 01 5030Z0#..*.H....
|
---|
1951 | * ^^- end 2016-10-05T07:50:30.000000000Z (161005075030Z)
|
---|
1952 | */
|
---|
1953 | PRTCRPKCS7ATTRIBUTE pAttr = SignToolPkcs7_AuthAttribAppend(pAuthAttribs);
|
---|
1954 | if (!pAttr)
|
---|
1955 | return RTEXITCODE_FAILURE;
|
---|
1956 |
|
---|
1957 | int rc = RTCrPkcs7Attribute_SetSigningTime(pAttr, NULL, pAuthAttribs->Allocation.pAllocator);
|
---|
1958 | if (RT_FAILURE(rc))
|
---|
1959 | return RTMsgErrorExitFailure("RTCrPkcs7Attribute_SetSigningTime failed: %Rrc", rc);
|
---|
1960 |
|
---|
1961 | /* Create the timestamp. */
|
---|
1962 | int32_t iPos = RTAsn1SetOfTimes_Append(pAttr->uValues.pSigningTime);
|
---|
1963 | if (iPos < 0)
|
---|
1964 | return RTMsgErrorExitFailure("RTAsn1SetOfTimes_Append failed: %Rrc", iPos);
|
---|
1965 |
|
---|
1966 | PRTASN1TIME pTime = pAttr->uValues.pSigningTime->papItems[iPos];
|
---|
1967 | rc = RTAsn1Time_SetTimeSpec(pTime, pAttr->Allocation.pAllocator, &SigningTime);
|
---|
1968 | if (RT_FAILURE(rc))
|
---|
1969 | return RTMsgErrorExitFailure("RTAsn1Time_SetTimeSpec failed: %Rrc", rc);
|
---|
1970 |
|
---|
1971 | return RTEXITCODE_SUCCESS;
|
---|
1972 | }
|
---|
1973 |
|
---|
1974 |
|
---|
1975 | static RTEXITCODE SignToolPkcs7_AuthAttribsAddSpcOpusInfo(PRTCRPKCS7ATTRIBUTES pAuthAttribs, void *pvInfo)
|
---|
1976 | {
|
---|
1977 | /** @todo The OpusInfo is a structure with an optional SpcString and an
|
---|
1978 | * optional SpcLink (url). The two attributes can be set using the /d and /du
|
---|
1979 | * options of MS signtool.exe, I think. We shouldn't be using them atm. */
|
---|
1980 |
|
---|
1981 | PRTCRPKCS7ATTRIBUTE pAttr = SignToolPkcs7_AuthAttribAppend(pAuthAttribs);
|
---|
1982 | if (!pAttr)
|
---|
1983 | return RTEXITCODE_FAILURE;
|
---|
1984 |
|
---|
1985 | int rc = RTCrPkcs7Attribute_SetMsStatementType(pAttr, NULL, pAuthAttribs->Allocation.pAllocator);
|
---|
1986 | if (RT_FAILURE(rc))
|
---|
1987 | return RTMsgErrorExitFailure("RTCrPkcs7Attribute_SetMsStatementType failed: %Rrc", rc);
|
---|
1988 |
|
---|
1989 | /* Override the ID. */
|
---|
1990 | rc = RTAsn1ObjId_SetFromString(&pAttr->Type, RTCR_PKCS9_ID_MS_SP_OPUS_INFO, pAuthAttribs->Allocation.pAllocator);
|
---|
1991 | if (RT_FAILURE(rc))
|
---|
1992 | return RTMsgErrorExitFailure("RTAsn1ObjId_SetFromString failed: %Rrc", rc);
|
---|
1993 |
|
---|
1994 | /* Add attribute value entry. */
|
---|
1995 | int32_t iPos = RTAsn1SetOfObjIdSeqs_Append(pAttr->uValues.pObjIdSeqs);
|
---|
1996 | if (iPos < 0)
|
---|
1997 | return RTMsgErrorExitFailure("RTAsn1SetOfObjIdSeqs_Append failed: %Rrc", iPos);
|
---|
1998 |
|
---|
1999 | RT_NOREF(pvInfo); Assert(!pvInfo);
|
---|
2000 | return RTEXITCODE_SUCCESS;
|
---|
2001 | }
|
---|
2002 |
|
---|
2003 |
|
---|
2004 | static RTEXITCODE SignToolPkcs7_AuthAttribsAddMsStatementType(PRTCRPKCS7ATTRIBUTES pAuthAttribs, const char *pszTypeId)
|
---|
2005 | {
|
---|
2006 | PRTCRPKCS7ATTRIBUTE pAttr = SignToolPkcs7_AuthAttribAppend(pAuthAttribs);
|
---|
2007 | if (!pAttr)
|
---|
2008 | return RTEXITCODE_FAILURE;
|
---|
2009 |
|
---|
2010 | int rc = RTCrPkcs7Attribute_SetMsStatementType(pAttr, NULL, pAuthAttribs->Allocation.pAllocator);
|
---|
2011 | if (RT_FAILURE(rc))
|
---|
2012 | return RTMsgErrorExitFailure("RTCrPkcs7Attribute_SetMsStatementType failed: %Rrc", rc);
|
---|
2013 |
|
---|
2014 | /* Add attribute value entry. */
|
---|
2015 | int32_t iPos = RTAsn1SetOfObjIdSeqs_Append(pAttr->uValues.pObjIdSeqs);
|
---|
2016 | if (iPos < 0)
|
---|
2017 | return RTMsgErrorExitFailure("RTAsn1SetOfObjIdSeqs_Append failed: %Rrc", iPos);
|
---|
2018 | PRTASN1SEQOFOBJIDS pSeqObjIds = pAttr->uValues.pObjIdSeqs->papItems[iPos];
|
---|
2019 |
|
---|
2020 | /* Add a object id to the value. */
|
---|
2021 | RTASN1OBJID ObjIdValue;
|
---|
2022 | rc = RTAsn1ObjId_InitFromString(&ObjIdValue, pszTypeId, &g_RTAsn1DefaultAllocator);
|
---|
2023 | if (RT_FAILURE(rc))
|
---|
2024 | return RTMsgErrorExitFailure("RTAsn1ObjId_InitFromString/%s failed: %Rrc", pszTypeId, rc);
|
---|
2025 |
|
---|
2026 | rc = RTAsn1SeqOfObjIds_InsertEx(pSeqObjIds, 0 /*iPos*/, &ObjIdValue, &g_RTAsn1DefaultAllocator, NULL);
|
---|
2027 | RTAsn1ObjId_Delete(&ObjIdValue);
|
---|
2028 | if (RT_FAILURE(rc))
|
---|
2029 | return RTMsgErrorExitFailure("RTAsn1SeqOfObjIds_InsertEx failed: %Rrc", rc);
|
---|
2030 |
|
---|
2031 | return RTEXITCODE_SUCCESS;
|
---|
2032 | }
|
---|
2033 |
|
---|
2034 |
|
---|
2035 | static RTEXITCODE SignToolPkcs7_AuthAttribsAddContentType(PRTCRPKCS7ATTRIBUTES pAuthAttribs, const char *pszContentTypeId)
|
---|
2036 | {
|
---|
2037 | PRTCRPKCS7ATTRIBUTE pAttr = SignToolPkcs7_AuthAttribAppend(pAuthAttribs);
|
---|
2038 | if (!pAttr)
|
---|
2039 | return RTEXITCODE_FAILURE;
|
---|
2040 |
|
---|
2041 | int rc = RTCrPkcs7Attribute_SetContentType(pAttr, NULL, pAuthAttribs->Allocation.pAllocator);
|
---|
2042 | if (RT_FAILURE(rc))
|
---|
2043 | return RTMsgErrorExitFailure("RTCrPkcs7Attribute_SetContentType failed: %Rrc", rc);
|
---|
2044 |
|
---|
2045 | /* Add a object id to the value. */
|
---|
2046 | RTASN1OBJID ObjIdValue;
|
---|
2047 | rc = RTAsn1ObjId_InitFromString(&ObjIdValue, pszContentTypeId, pAuthAttribs->Allocation.pAllocator);
|
---|
2048 | if (RT_FAILURE(rc))
|
---|
2049 | return RTMsgErrorExitFailure("RTAsn1ObjId_InitFromString/%s failed: %Rrc", pszContentTypeId, rc);
|
---|
2050 |
|
---|
2051 | rc = RTAsn1SetOfObjIds_InsertEx(pAttr->uValues.pObjIds, 0 /*iPos*/, &ObjIdValue, pAuthAttribs->Allocation.pAllocator, NULL);
|
---|
2052 | RTAsn1ObjId_Delete(&ObjIdValue);
|
---|
2053 | if (RT_FAILURE(rc))
|
---|
2054 | return RTMsgErrorExitFailure("RTAsn1SetOfObjIds_InsertEx failed: %Rrc", rc);
|
---|
2055 |
|
---|
2056 | return RTEXITCODE_SUCCESS;
|
---|
2057 | }
|
---|
2058 |
|
---|
2059 |
|
---|
2060 | static RTEXITCODE SignToolPkcs7_AddAuthAttribsForTimestamp(PRTCRPKCS7ATTRIBUTES pAuthAttribs, TIMESTAMPTYPE enmTimestampType,
|
---|
2061 | RTTIMESPEC SigningTime, PCRTCRX509CERTIFICATE pTimestampCert)
|
---|
2062 | {
|
---|
2063 | /*
|
---|
2064 | * Add content type.
|
---|
2065 | */
|
---|
2066 | RTEXITCODE rcExit = SignToolPkcs7_AuthAttribsAddContentType(pAuthAttribs,
|
---|
2067 | enmTimestampType == kTimestampType_Old
|
---|
2068 | ? RTCR_PKCS7_DATA_OID : RTCRTSPTSTINFO_OID);
|
---|
2069 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
2070 | return rcExit;
|
---|
2071 |
|
---|
2072 | /*
|
---|
2073 | * Add signing time.
|
---|
2074 | */
|
---|
2075 | rcExit = SignToolPkcs7_AuthAttribsAddSigningTime(pAuthAttribs, SigningTime);
|
---|
2076 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
2077 | return rcExit;
|
---|
2078 |
|
---|
2079 | /*
|
---|
2080 | * More later if we want to support fTimestampTypeOld = false perhaps?
|
---|
2081 | */
|
---|
2082 | Assert(enmTimestampType == kTimestampType_Old);
|
---|
2083 | RT_NOREF(pTimestampCert);
|
---|
2084 |
|
---|
2085 | return RTEXITCODE_SUCCESS;
|
---|
2086 | }
|
---|
2087 |
|
---|
2088 |
|
---|
2089 | static RTEXITCODE SignToolPkcs7_AddAuthAttribsForImageOrCatSignature(PRTCRPKCS7ATTRIBUTES pAuthAttribs, RTTIMESPEC SigningTime,
|
---|
2090 | bool fNoSigningTime, const char *pszContentTypeId)
|
---|
2091 | {
|
---|
2092 | /*
|
---|
2093 | * Add SpcOpusInfo. No attribute values.
|
---|
2094 | * SEQ start -vv vv- Type ObjId
|
---|
2095 | * 1c60: 0e 03 02 1a 05 00 a0 70-30 10 06 0a 2b 06 01 04 .......p0...+...
|
---|
2096 | * 1c70: 01 82 37 02 01 0c 31 02-30 00 30 19 06 09 2a 86 ..7...1.0.0...*.
|
---|
2097 | * Set Of -^^ ^^- Empty Sequence.
|
---|
2098 | */
|
---|
2099 | RTEXITCODE rcExit = SignToolPkcs7_AuthAttribsAddSpcOpusInfo(pAuthAttribs, NULL /*pvInfo - none*/);
|
---|
2100 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
2101 | return rcExit;
|
---|
2102 |
|
---|
2103 | /*
|
---|
2104 | * Add ContentType = Ms-SpcIndirectDataContext?
|
---|
2105 | * SEQ start -vv vv- Type ObjId
|
---|
2106 | * 1c70: 01 82 37 02 01 0c 31 02-30 00 30 19 06 09 2a 86 ..7...1.0.0...*.
|
---|
2107 | * 1c80: 48 86 f7 0d 01 09 03 31-0c 06 0a 2b 06 01 04 01 H......1...+....
|
---|
2108 | * 1c90: 82 37 02 01 04 ^^- ^^- ObjId
|
---|
2109 | * ^- Set Of
|
---|
2110 | */
|
---|
2111 | rcExit = SignToolPkcs7_AuthAttribsAddContentType(pAuthAttribs, pszContentTypeId);
|
---|
2112 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
2113 | return rcExit;
|
---|
2114 |
|
---|
2115 | /*
|
---|
2116 | * Add Ms-SpcStatementType = Ms-SpcIndividualCodeSigning.
|
---|
2117 | * SEQ start -vv vv- Type ObjId
|
---|
2118 | * 1c90: 82 37 02 01 04 30 1c 06-0a 2b 06 01 04 01 82 37 .7...0...+.....7
|
---|
2119 | * 1ca0: 02 01 0b 31 0e 30 0c 06-0a 2b 06 01 04 01 82 37 ...1.0...+.....7
|
---|
2120 | * 1cb0: 02 01 15 ^^ ^^ ^^- ObjId
|
---|
2121 | * Set Of -^^ ^^- Sequence Of
|
---|
2122 | */
|
---|
2123 | rcExit = SignToolPkcs7_AuthAttribsAddMsStatementType(pAuthAttribs, RTCRSPC_STMT_TYPE_INDIVIDUAL_CODE_SIGNING);
|
---|
2124 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
2125 | return rcExit;
|
---|
2126 |
|
---|
2127 | /*
|
---|
2128 | * Add signing time. We add this, even if signtool.exe, since OpenSSL will always do it otherwise.
|
---|
2129 | */
|
---|
2130 | if (!fNoSigningTime) /** @todo requires disabling the code in do_pkcs7_signed_attrib that adds it when absent */
|
---|
2131 | {
|
---|
2132 | rcExit = SignToolPkcs7_AuthAttribsAddSigningTime(pAuthAttribs, SigningTime);
|
---|
2133 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
2134 | return rcExit;
|
---|
2135 | }
|
---|
2136 |
|
---|
2137 | /** @todo more? Some certificate stuff? */
|
---|
2138 |
|
---|
2139 | return RTEXITCODE_SUCCESS;
|
---|
2140 | }
|
---|
2141 |
|
---|
2142 |
|
---|
2143 | static RTEXITCODE SignToolPkcs7_AppendCounterSignature(PRTCRPKCS7SIGNERINFO pSignerInfo,
|
---|
2144 | PCRTCRPKCS7SIGNERINFO pCounterSignerInfo, unsigned cVerbosity)
|
---|
2145 | {
|
---|
2146 | /* Make sure the UnauthenticatedAttributes member is there. */
|
---|
2147 | RTEXITCODE rcExit = SignToolPkcs7_EnsureUnauthenticatedAttributesPresent(pSignerInfo);
|
---|
2148 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
2149 | return rcExit;
|
---|
2150 |
|
---|
2151 | #if 0 /* Windows won't accept multiple timestamps either way. Doing the latter as it makes more sense to me... */
|
---|
2152 | /* Append an entry to UnauthenticatedAttributes. */
|
---|
2153 | uint32_t iPos;
|
---|
2154 | int rc = RTCrPkcs7Attributes_InsertEx(&pSignerInfo->UnauthenticatedAttributes, 0 /*iPosition*/, NULL /*pToClone*/,
|
---|
2155 | &g_RTAsn1DefaultAllocator, &iPos);
|
---|
2156 | if (RT_FAILURE(rc))
|
---|
2157 | return RTMsgErrorExitFailure("RTCrPkcs7Attributes_Append failed: %Rrc", rc);
|
---|
2158 | Assert(iPos < pSignerInfo->UnauthenticatedAttributes.cItems); Assert(iPos == 0);
|
---|
2159 | PRTCRPKCS7ATTRIBUTE pAttr = pSignerInfo->UnauthenticatedAttributes.papItems[iPos];
|
---|
2160 |
|
---|
2161 | if (cVerbosity >= 2)
|
---|
2162 | RTMsgInfo("Adding UnauthenticatedAttribute #%u...", iPos);
|
---|
2163 | #else
|
---|
2164 | /* Look up the counter signature attribute, create one if needed. */
|
---|
2165 | int rc;
|
---|
2166 | uint32_t iPos = 0;
|
---|
2167 | PRTCRPKCS7ATTRIBUTE pAttr = NULL;
|
---|
2168 | for (; iPos < pSignerInfo->UnauthenticatedAttributes.cItems; iPos++)
|
---|
2169 | {
|
---|
2170 | pAttr = pSignerInfo->UnauthenticatedAttributes.papItems[iPos];
|
---|
2171 | if (pAttr->enmType == RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES)
|
---|
2172 | break;
|
---|
2173 | }
|
---|
2174 | if (iPos >= pSignerInfo->UnauthenticatedAttributes.cItems)
|
---|
2175 | {
|
---|
2176 | /* Append a new entry to UnauthenticatedAttributes. */
|
---|
2177 | rc = RTCrPkcs7Attributes_InsertEx(&pSignerInfo->UnauthenticatedAttributes, 0 /*iPosition*/, NULL /*pToClone*/,
|
---|
2178 | &g_RTAsn1DefaultAllocator, &iPos);
|
---|
2179 | if (RT_FAILURE(rc))
|
---|
2180 | return RTMsgErrorExitFailure("RTCrPkcs7Attributes_Append failed: %Rrc", rc);
|
---|
2181 | Assert(iPos < pSignerInfo->UnauthenticatedAttributes.cItems); Assert(iPos == 0);
|
---|
2182 | pAttr = pSignerInfo->UnauthenticatedAttributes.papItems[iPos];
|
---|
2183 |
|
---|
2184 | /* Create the attrib and its sub-set of counter signatures. */
|
---|
2185 | rc = RTCrPkcs7Attribute_SetCounterSignatures(pAttr, NULL, pAttr->Allocation.pAllocator);
|
---|
2186 | if (RT_FAILURE(rc))
|
---|
2187 | return RTMsgErrorExitFailure("RTCrPkcs7Attribute_SetCounterSignatures failed: %Rrc", rc);
|
---|
2188 | }
|
---|
2189 |
|
---|
2190 | if (cVerbosity >= 2)
|
---|
2191 | RTMsgInfo("Adding UnauthenticatedAttribute #%u.%u...", iPos, pAttr->uValues.pCounterSignatures->cItems);
|
---|
2192 |
|
---|
2193 | #endif
|
---|
2194 |
|
---|
2195 | /* Insert the counter signature. */
|
---|
2196 | rc = RTCrPkcs7SignerInfos_InsertEx(pAttr->uValues.pCounterSignatures, pAttr->uValues.pCounterSignatures->cItems /*iPosition*/,
|
---|
2197 | pCounterSignerInfo, pAttr->Allocation.pAllocator, NULL);
|
---|
2198 | if (RT_FAILURE(rc))
|
---|
2199 | return RTMsgErrorExitFailure("RTCrPkcs7SignerInfos_InsertEx failed: %Rrc", rc);
|
---|
2200 |
|
---|
2201 | return RTEXITCODE_SUCCESS;
|
---|
2202 | }
|
---|
2203 |
|
---|
2204 |
|
---|
2205 | static RTEXITCODE SignToolPkcs7_AppendCertificate(PRTCRPKCS7SIGNEDDATA pSignedData, PCRTCRX509CERTIFICATE pCertToAppend)
|
---|
2206 | {
|
---|
2207 | if (pSignedData->Certificates.cItems == 0 && !RTCrPkcs7SetOfCerts_IsPresent(&pSignedData->Certificates))
|
---|
2208 | return RTMsgErrorExitFailure("PKCS#7 signature includes no certificates! Didn't expect that");
|
---|
2209 |
|
---|
2210 | /* Already there? */
|
---|
2211 | PCRTCRX509CERTIFICATE pExisting
|
---|
2212 | = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSignedData->Certificates, &pCertToAppend->TbsCertificate.Issuer,
|
---|
2213 | &pCertToAppend->TbsCertificate.SerialNumber);
|
---|
2214 | if (!pExisting || RTCrX509Certificate_Compare(pExisting, pCertToAppend) != 0)
|
---|
2215 | {
|
---|
2216 | /* Prepend a RTCRPKCS7CERT entry. */
|
---|
2217 | uint32_t iPos;
|
---|
2218 | int rc = RTCrPkcs7SetOfCerts_InsertEx(&pSignedData->Certificates, 0 /*iPosition*/, NULL /*pToClone*/,
|
---|
2219 | &g_RTAsn1DefaultAllocator, &iPos);
|
---|
2220 | if (RT_FAILURE(rc))
|
---|
2221 | return RTMsgErrorExitFailure("RTCrPkcs7SetOfCerts_Append failed: %Rrc", rc);
|
---|
2222 | PRTCRPKCS7CERT pCertEntry = pSignedData->Certificates.papItems[iPos];
|
---|
2223 |
|
---|
2224 | /* Set (clone) the certificate. */
|
---|
2225 | rc = RTCrPkcs7Cert_SetX509Cert(pCertEntry, pCertToAppend, pCertEntry->Allocation.pAllocator);
|
---|
2226 | if (RT_FAILURE(rc))
|
---|
2227 | return RTMsgErrorExitFailure("RTCrPkcs7Cert_X509Cert failed: %Rrc", rc);
|
---|
2228 | }
|
---|
2229 | return RTEXITCODE_SUCCESS;
|
---|
2230 | }
|
---|
2231 |
|
---|
2232 | #ifdef RT_OS_WINDOWS
|
---|
2233 |
|
---|
2234 | static PCRTUTF16 GetBCryptNameFromCrDigest(RTCRDIGEST hDigest)
|
---|
2235 | {
|
---|
2236 | switch (RTCrDigestGetType(hDigest))
|
---|
2237 | {
|
---|
2238 | case RTDIGESTTYPE_MD2: return BCRYPT_MD2_ALGORITHM;
|
---|
2239 | case RTDIGESTTYPE_MD4: return BCRYPT_MD4_ALGORITHM;
|
---|
2240 | case RTDIGESTTYPE_SHA1: return BCRYPT_SHA1_ALGORITHM;
|
---|
2241 | case RTDIGESTTYPE_SHA256: return BCRYPT_SHA256_ALGORITHM;
|
---|
2242 | case RTDIGESTTYPE_SHA384: return BCRYPT_SHA384_ALGORITHM;
|
---|
2243 | case RTDIGESTTYPE_SHA512: return BCRYPT_SHA512_ALGORITHM;
|
---|
2244 | default:
|
---|
2245 | RTMsgError("No BCrypt translation for %s/%d!", RTCrDigestGetAlgorithmOid(hDigest), RTCrDigestGetType(hDigest));
|
---|
2246 | return L"No BCrypt translation";
|
---|
2247 | }
|
---|
2248 | }
|
---|
2249 |
|
---|
2250 | static RTEXITCODE
|
---|
2251 | SignToolPkcs7_Pkcs7SignStuffAgainWithReal(const char *pszWhat, SignToolKeyPair *pCertKeyPair, unsigned cVerbosity,
|
---|
2252 | PRTCRPKCS7CONTENTINFO pContentInfo, void **ppvSigned, size_t *pcbSigned)
|
---|
2253 |
|
---|
2254 | {
|
---|
2255 | RT_NOREF(cVerbosity);
|
---|
2256 |
|
---|
2257 | /*
|
---|
2258 | * First remove the fake certificate from the PKCS7 structure and insert the real one.
|
---|
2259 | */
|
---|
2260 | PRTCRPKCS7SIGNEDDATA pSignedData = pContentInfo->u.pSignedData;
|
---|
2261 | unsigned iCert = pSignedData->Certificates.cItems;
|
---|
2262 | unsigned cErased = 0;
|
---|
2263 | while (iCert-- > 0)
|
---|
2264 | {
|
---|
2265 | PCRTCRPKCS7CERT pCert = pSignedData->Certificates.papItems[iCert];
|
---|
2266 | if ( pCert->enmChoice == RTCRPKCS7CERTCHOICE_X509
|
---|
2267 | && RTCrX509Certificate_MatchIssuerAndSerialNumber(pCert->u.pX509Cert,
|
---|
2268 | &pCertKeyPair->pCertificate->TbsCertificate.Issuer,
|
---|
2269 | &pCertKeyPair->pCertificate->TbsCertificate.SerialNumber))
|
---|
2270 | {
|
---|
2271 | RTCrPkcs7SetOfCerts_Erase(&pSignedData->Certificates, iCert);
|
---|
2272 | cErased++;
|
---|
2273 | }
|
---|
2274 | }
|
---|
2275 | if (cErased == 0)
|
---|
2276 | return RTMsgErrorExitFailure("(%s) Failed to find temporary signing certificate in PKCS#7 from OpenSSL: %u certs",
|
---|
2277 | pszWhat, pSignedData->Certificates.cItems);
|
---|
2278 |
|
---|
2279 | /* Then insert the real signing certificate. */
|
---|
2280 | PCRTCRX509CERTIFICATE const pRealCertificate = pCertKeyPair->getRealCertificate();
|
---|
2281 | RTEXITCODE rcExit = SignToolPkcs7_AppendCertificate(pSignedData, pRealCertificate);
|
---|
2282 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
2283 | return rcExit;
|
---|
2284 |
|
---|
2285 | /*
|
---|
2286 | * Modify the signer info to reflect the real certificate.
|
---|
2287 | */
|
---|
2288 | PRTCRPKCS7SIGNERINFO pSignerInfo = pSignedData->SignerInfos.papItems[0];
|
---|
2289 | RTCrX509Name_Delete(&pSignerInfo->IssuerAndSerialNumber.Name);
|
---|
2290 | int rc = RTCrX509Name_Clone(&pSignerInfo->IssuerAndSerialNumber.Name,
|
---|
2291 | &pRealCertificate->TbsCertificate.Issuer, &g_RTAsn1DefaultAllocator);
|
---|
2292 | if (RT_FAILURE(rc))
|
---|
2293 | return RTMsgErrorExitFailure("(%s) RTCrX509Name_Clone failed: %Rrc", pszWhat, rc);
|
---|
2294 |
|
---|
2295 | RTAsn1Integer_Delete(&pSignerInfo->IssuerAndSerialNumber.SerialNumber);
|
---|
2296 | rc = RTAsn1Integer_Clone(&pSignerInfo->IssuerAndSerialNumber.SerialNumber,
|
---|
2297 | &pRealCertificate->TbsCertificate.SerialNumber, &g_RTAsn1DefaultAllocator);
|
---|
2298 | if (RT_FAILURE(rc))
|
---|
2299 | return RTMsgErrorExitFailure("(%s) RTAsn1Integer_Clone failed: %Rrc", pszWhat, rc);
|
---|
2300 |
|
---|
2301 | /* There shouldn't be anything in the authenticated attributes that
|
---|
2302 | we need to modify... */
|
---|
2303 |
|
---|
2304 | /*
|
---|
2305 | * Now a create a new signature using the real key. Since we haven't modified
|
---|
2306 | * the authenticated attributes, we can just hash them as-is.
|
---|
2307 | */
|
---|
2308 | /* Create the hash to sign. */
|
---|
2309 | RTCRDIGEST hDigest;
|
---|
2310 | rc = RTCrDigestCreateByObjId(&hDigest, &pSignerInfo->DigestAlgorithm.Algorithm);
|
---|
2311 | if (RT_FAILURE(rc))
|
---|
2312 | return RTMsgErrorExitFailure("(%s) RTCrDigestCreateByObjId failed on '%s': %Rrc",
|
---|
2313 | pszWhat, pSignerInfo->DigestAlgorithm.Algorithm.szObjId, rc);
|
---|
2314 |
|
---|
2315 | rcExit = RTEXITCODE_FAILURE;
|
---|
2316 | RTERRINFOSTATIC ErrInfo;
|
---|
2317 | rc = RTCrPkcs7Attributes_HashAttributes(&pSignerInfo->AuthenticatedAttributes, hDigest, RTErrInfoInitStatic(&ErrInfo));
|
---|
2318 | if (RT_SUCCESS(rc))
|
---|
2319 | {
|
---|
2320 | BCRYPT_PKCS1_PADDING_INFO PaddingInfo = { GetBCryptNameFromCrDigest(hDigest) };
|
---|
2321 | DWORD cbSignature = 0;
|
---|
2322 | SECURITY_STATUS rcNCrypt = NCryptSignHash(pCertKeyPair->hNCryptPrivateKey, &PaddingInfo,
|
---|
2323 | (PBYTE)RTCrDigestGetHash(hDigest), RTCrDigestGetHashSize(hDigest),
|
---|
2324 | NULL, 0, &cbSignature, NCRYPT_SILENT_FLAG | BCRYPT_PAD_PKCS1);
|
---|
2325 | if (rcNCrypt == ERROR_SUCCESS)
|
---|
2326 | {
|
---|
2327 | if (cVerbosity)
|
---|
2328 | RTMsgInfo("PaddingInfo: '%ls' cb=%#x, was %#zx\n",
|
---|
2329 | PaddingInfo.pszAlgId, cbSignature, pSignerInfo->EncryptedDigest.Asn1Core.cb);
|
---|
2330 |
|
---|
2331 | rc = RTAsn1OctetString_AllocContent(&pSignerInfo->EncryptedDigest, NULL /*pvSrc*/, cbSignature,
|
---|
2332 | &g_RTAsn1DefaultAllocator);
|
---|
2333 | if (RT_SUCCESS(rc))
|
---|
2334 | {
|
---|
2335 | Assert(pSignerInfo->EncryptedDigest.Asn1Core.uData.pv);
|
---|
2336 | rcNCrypt = NCryptSignHash(pCertKeyPair->hNCryptPrivateKey, &PaddingInfo,
|
---|
2337 | (PBYTE)RTCrDigestGetHash(hDigest), RTCrDigestGetHashSize(hDigest),
|
---|
2338 | (PBYTE)pSignerInfo->EncryptedDigest.Asn1Core.uData.pv, cbSignature, &cbSignature,
|
---|
2339 | /*NCRYPT_SILENT_FLAG |*/ BCRYPT_PAD_PKCS1);
|
---|
2340 | if (rcNCrypt == ERROR_SUCCESS)
|
---|
2341 | {
|
---|
2342 | /*
|
---|
2343 | * Now we need to re-encode the whole thing and decode it again.
|
---|
2344 | */
|
---|
2345 | PRTASN1CORE pRoot = RTCrPkcs7ContentInfo_GetAsn1Core(pContentInfo);
|
---|
2346 | uint32_t cbRealSigned;
|
---|
2347 | rc = RTAsn1EncodePrepare(pRoot, RTASN1ENCODE_F_DER, &cbRealSigned, RTErrInfoInitStatic(&ErrInfo));
|
---|
2348 | if (RT_SUCCESS(rc))
|
---|
2349 | {
|
---|
2350 | void *pvRealSigned = RTMemAllocZ(cbRealSigned);
|
---|
2351 | if (pvRealSigned)
|
---|
2352 | {
|
---|
2353 | rc = RTAsn1EncodeToBuffer(pRoot, RTASN1ENCODE_F_DER, pvRealSigned, cbRealSigned,
|
---|
2354 | RTErrInfoInitStatic(&ErrInfo));
|
---|
2355 | if (RT_SUCCESS(rc))
|
---|
2356 | {
|
---|
2357 | /* Decode it */
|
---|
2358 | RTCrPkcs7ContentInfo_Delete(pContentInfo);
|
---|
2359 |
|
---|
2360 | RTASN1CURSORPRIMARY PrimaryCursor;
|
---|
2361 | RTAsn1CursorInitPrimary(&PrimaryCursor, pvRealSigned, cbRealSigned, RTErrInfoInitStatic(&ErrInfo),
|
---|
2362 | &g_RTAsn1DefaultAllocator, 0, pszWhat);
|
---|
2363 | rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, pContentInfo, "CI");
|
---|
2364 | if (RT_SUCCESS(rc))
|
---|
2365 | {
|
---|
2366 | Assert(RTCrPkcs7ContentInfo_IsSignedData(pContentInfo));
|
---|
2367 |
|
---|
2368 | /* Almost done! Just replace output buffer. */
|
---|
2369 | RTMemFree(*ppvSigned);
|
---|
2370 | *ppvSigned = pvRealSigned;
|
---|
2371 | *pcbSigned = cbRealSigned;
|
---|
2372 | pvRealSigned = NULL;
|
---|
2373 | rcExit = RTEXITCODE_SUCCESS;
|
---|
2374 | }
|
---|
2375 | else
|
---|
2376 | RTMsgError("(%s) RTCrPkcs7ContentInfo_DecodeAsn1 failed: %Rrc%#RTeim",
|
---|
2377 | pszWhat, rc, &ErrInfo.Core);
|
---|
2378 | }
|
---|
2379 | else
|
---|
2380 | RTMsgError("(%s) RTAsn1EncodeToBuffer failed: %Rrc%#RTeim", pszWhat, rc, &ErrInfo.Core);
|
---|
2381 |
|
---|
2382 | RTMemFree(pvRealSigned);
|
---|
2383 | }
|
---|
2384 | else
|
---|
2385 | RTMsgError("(%s) Failed to allocate %u bytes!", pszWhat, cbRealSigned);
|
---|
2386 | }
|
---|
2387 | else
|
---|
2388 | RTMsgError("(%s) RTAsn1EncodePrepare failed: %Rrc%#RTeim", pszWhat, rc, &ErrInfo.Core);
|
---|
2389 | }
|
---|
2390 | else
|
---|
2391 | RTMsgError("(%s) NCryptSignHash/2 failed: %Rwc %#x (%u)", pszWhat, rcNCrypt, rcNCrypt, rcNCrypt);
|
---|
2392 | }
|
---|
2393 | else
|
---|
2394 | RTMsgError("(%s) RTAsn1OctetString_AllocContent(,,%#x) failed: %Rrc", pszWhat, cbSignature, rc);
|
---|
2395 | }
|
---|
2396 | else
|
---|
2397 | RTMsgError("(%s) NCryptSignHash/1 failed: %Rwc %#x (%u)", pszWhat, rcNCrypt, rcNCrypt, rcNCrypt);
|
---|
2398 | }
|
---|
2399 | else
|
---|
2400 | RTMsgError("(%s) RTCrPkcs7Attributes_HashAttributes failed: %Rrc%#RTeim", pszWhat, rc, &ErrInfo.Core);
|
---|
2401 | RTCrDigestRelease(hDigest);
|
---|
2402 | return rcExit;
|
---|
2403 | }
|
---|
2404 |
|
---|
2405 | #endif /* RT_OS_WINDOWS */
|
---|
2406 |
|
---|
2407 | static RTEXITCODE SignToolPkcs7_Pkcs7SignStuffInner(const char *pszWhat, const void *pvToDataToSign, size_t cbToDataToSign,
|
---|
2408 | PCRTCRPKCS7ATTRIBUTES pAuthAttribs, RTCRSTORE hAdditionalCerts,
|
---|
2409 | uint32_t fExtraFlags, RTDIGESTTYPE enmDigestType,
|
---|
2410 | SignToolKeyPair *pCertKeyPair, unsigned cVerbosity,
|
---|
2411 | void **ppvSigned, size_t *pcbSigned, PRTCRPKCS7CONTENTINFO pContentInfo,
|
---|
2412 | PRTCRPKCS7SIGNEDDATA *ppSignedData)
|
---|
2413 | {
|
---|
2414 | *ppvSigned = NULL;
|
---|
2415 | if (pcbSigned)
|
---|
2416 | *pcbSigned = 0;
|
---|
2417 | if (ppSignedData)
|
---|
2418 | *ppSignedData = NULL;
|
---|
2419 |
|
---|
2420 | /* Figure out how large the signature will be. */
|
---|
2421 | uint32_t const fSignFlags = RTCRPKCS7SIGN_SD_F_USE_V1 | RTCRPKCS7SIGN_SD_F_NO_SMIME_CAP | fExtraFlags;
|
---|
2422 | size_t cbSigned = 1024;
|
---|
2423 | RTERRINFOSTATIC ErrInfo;
|
---|
2424 | int rc = RTCrPkcs7SimpleSignSignedData(fSignFlags, pCertKeyPair->pCertificate, pCertKeyPair->hPrivateKey,
|
---|
2425 | pvToDataToSign, cbToDataToSign,enmDigestType, hAdditionalCerts, pAuthAttribs,
|
---|
2426 | NULL, &cbSigned, RTErrInfoInitStatic(&ErrInfo));
|
---|
2427 | if (rc != VERR_BUFFER_OVERFLOW)
|
---|
2428 | return RTMsgErrorExitFailure("(%s) RTCrPkcs7SimpleSignSignedData failed: %Rrc%#RTeim", pszWhat, rc, &ErrInfo.Core);
|
---|
2429 |
|
---|
2430 | /* Allocate memory for it and do the actual signing. */
|
---|
2431 | void *pvSigned = RTMemAllocZ(cbSigned);
|
---|
2432 | if (!pvSigned)
|
---|
2433 | return RTMsgErrorExitFailure("(%s) Failed to allocate %#zx bytes for %s signature", pszWhat, cbSigned, pszWhat);
|
---|
2434 | rc = RTCrPkcs7SimpleSignSignedData(fSignFlags, pCertKeyPair->pCertificate, pCertKeyPair->hPrivateKey,
|
---|
2435 | pvToDataToSign, cbToDataToSign, enmDigestType, hAdditionalCerts, pAuthAttribs,
|
---|
2436 | pvSigned, &cbSigned, RTErrInfoInitStatic(&ErrInfo));
|
---|
2437 | if (RT_SUCCESS(rc))
|
---|
2438 | {
|
---|
2439 | if (cVerbosity > 2)
|
---|
2440 | RTMsgInfo("%s signature: %#zx bytes\n%.*Rhxd\n", pszWhat, cbSigned, cbSigned, pvSigned);
|
---|
2441 |
|
---|
2442 | /*
|
---|
2443 | * Decode the signature and check that it is SignedData.
|
---|
2444 | */
|
---|
2445 | RTASN1CURSORPRIMARY PrimaryCursor;
|
---|
2446 | RTAsn1CursorInitPrimary(&PrimaryCursor, pvSigned, (uint32_t)cbSigned, RTErrInfoInitStatic(&ErrInfo),
|
---|
2447 | &g_RTAsn1DefaultAllocator, 0, pszWhat);
|
---|
2448 | rc = RTCrPkcs7ContentInfo_DecodeAsn1(&PrimaryCursor.Cursor, 0, pContentInfo, "CI");
|
---|
2449 | if (RT_SUCCESS(rc))
|
---|
2450 | {
|
---|
2451 | if (RTCrPkcs7ContentInfo_IsSignedData(pContentInfo))
|
---|
2452 | {
|
---|
2453 | #ifdef RT_OS_WINDOWS
|
---|
2454 | /*
|
---|
2455 | * If we're using a fake key+cert, we now have to re-do the signing using the real
|
---|
2456 | * key+cert and the windows crypto API. This kludge is necessary because we can't
|
---|
2457 | * typically get that the encoded private key, so it isn't possible to feed it to
|
---|
2458 | * openssl.
|
---|
2459 | */
|
---|
2460 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
2461 | if (pCertKeyPair->pCertificateReal)
|
---|
2462 | rcExit = SignToolPkcs7_Pkcs7SignStuffAgainWithReal(pszWhat, pCertKeyPair, cVerbosity, pContentInfo,
|
---|
2463 | &pvSigned, &cbSigned);
|
---|
2464 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
2465 | #endif
|
---|
2466 | {
|
---|
2467 | /*
|
---|
2468 | * Set returns and maybe display the result before returning.
|
---|
2469 | */
|
---|
2470 | *ppvSigned = pvSigned;
|
---|
2471 | if (pcbSigned)
|
---|
2472 | *pcbSigned = cbSigned;
|
---|
2473 | if (ppSignedData)
|
---|
2474 | *ppSignedData = pContentInfo->u.pSignedData;
|
---|
2475 |
|
---|
2476 | if (cVerbosity)
|
---|
2477 | {
|
---|
2478 | SHOWEXEPKCS7 ShowExe;
|
---|
2479 | RT_ZERO(ShowExe);
|
---|
2480 | ShowExe.cVerbosity = cVerbosity;
|
---|
2481 | HandleShowExeWorkerPkcs7Display(&ShowExe, pContentInfo->u.pSignedData, 0, pContentInfo);
|
---|
2482 | }
|
---|
2483 | return RTEXITCODE_SUCCESS;
|
---|
2484 | }
|
---|
2485 | }
|
---|
2486 |
|
---|
2487 | RTMsgError("(%s) RTCrPkcs7SimpleSignSignedData did not create SignedData: %s",
|
---|
2488 | pszWhat, pContentInfo->ContentType.szObjId);
|
---|
2489 | }
|
---|
2490 | else
|
---|
2491 | RTMsgError("(%s) RTCrPkcs7ContentInfo_DecodeAsn1 failed: %Rrc%#RTeim", pszWhat, rc, &ErrInfo.Core);
|
---|
2492 | RTCrPkcs7ContentInfo_Delete(pContentInfo);
|
---|
2493 | }
|
---|
2494 | RTMemFree(pvSigned);
|
---|
2495 | return RTEXITCODE_FAILURE;
|
---|
2496 | }
|
---|
2497 |
|
---|
2498 |
|
---|
2499 | static RTEXITCODE SignToolPkcs7_Pkcs7SignStuff(const char *pszWhat, const void *pvToDataToSign, size_t cbToDataToSign,
|
---|
2500 | PCRTCRPKCS7ATTRIBUTES pAuthAttribs, RTCRSTORE hAdditionalCerts,
|
---|
2501 | uint32_t fExtraFlags, RTDIGESTTYPE enmDigestType, SignToolKeyPair *pCertKeyPair,
|
---|
2502 | unsigned cVerbosity, void **ppvSigned, size_t *pcbSigned,
|
---|
2503 | PRTCRPKCS7CONTENTINFO pContentInfo, PRTCRPKCS7SIGNEDDATA *ppSignedData)
|
---|
2504 | {
|
---|
2505 | /*
|
---|
2506 | * Gather all additional certificates before doing the actual work.
|
---|
2507 | */
|
---|
2508 | RTCRSTORE hAllAdditionalCerts = pCertKeyPair->assembleAllAdditionalCertificates(hAdditionalCerts);
|
---|
2509 | if (hAllAdditionalCerts == NIL_RTCRSTORE)
|
---|
2510 | return RTEXITCODE_FAILURE;
|
---|
2511 | RTEXITCODE rcExit = SignToolPkcs7_Pkcs7SignStuffInner(pszWhat, pvToDataToSign, cbToDataToSign, pAuthAttribs,
|
---|
2512 | hAllAdditionalCerts, fExtraFlags, enmDigestType, pCertKeyPair,
|
---|
2513 | cVerbosity, ppvSigned, pcbSigned, pContentInfo, ppSignedData);
|
---|
2514 | RTCrStoreRelease(hAllAdditionalCerts);
|
---|
2515 | return rcExit;
|
---|
2516 | }
|
---|
2517 |
|
---|
2518 |
|
---|
2519 | static RTEXITCODE SignToolPkcs7_AddTimestampSignatureEx(PRTCRPKCS7SIGNERINFO pSignerInfo, PRTCRPKCS7SIGNEDDATA pSignedData,
|
---|
2520 | unsigned cVerbosity, bool fReplaceExisting,
|
---|
2521 | RTTIMESPEC SigningTime, SignToolTimestampOpts *pTimestampOpts)
|
---|
2522 | {
|
---|
2523 | AssertReturn(!pTimestampOpts->isNewType(), RTMsgErrorExitFailure("New style signatures not supported yet"));
|
---|
2524 |
|
---|
2525 | /*
|
---|
2526 | * Create a set of attributes we need to include in the AuthenticatedAttributes
|
---|
2527 | * of the timestamp signature.
|
---|
2528 | */
|
---|
2529 | RTCRPKCS7ATTRIBUTES AuthAttribs;
|
---|
2530 | int rc = RTCrPkcs7Attributes_Init(&AuthAttribs, &g_RTAsn1DefaultAllocator);
|
---|
2531 | if (RT_FAILURE(rc))
|
---|
2532 | return RTMsgErrorExitFailure("RTCrPkcs7SetOfAttributes_Init failed: %Rrc", rc);
|
---|
2533 |
|
---|
2534 | RTEXITCODE rcExit = SignToolPkcs7_AddAuthAttribsForTimestamp(&AuthAttribs, pTimestampOpts->m_enmType, SigningTime,
|
---|
2535 | pTimestampOpts->getRealCertificate());
|
---|
2536 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
2537 | {
|
---|
2538 | /*
|
---|
2539 | * Now create a PKCS#7 signature of the encrypted signature from the selected signer info.
|
---|
2540 | */
|
---|
2541 | void *pvSigned = NULL;
|
---|
2542 | PRTCRPKCS7SIGNEDDATA pTsSignedData = NULL;
|
---|
2543 | RTCRPKCS7CONTENTINFO TsContentInfo;
|
---|
2544 | rcExit = SignToolPkcs7_Pkcs7SignStuffInner("timestamp", pSignerInfo->EncryptedDigest.Asn1Core.uData.pv,
|
---|
2545 | pSignerInfo->EncryptedDigest.Asn1Core.cb, &AuthAttribs,
|
---|
2546 | NIL_RTCRSTORE /*hAdditionalCerts*/, RTCRPKCS7SIGN_SD_F_DEATCHED,
|
---|
2547 | RTDIGESTTYPE_SHA1, pTimestampOpts, cVerbosity,
|
---|
2548 | &pvSigned, NULL /*pcbSigned*/, &TsContentInfo, &pTsSignedData);
|
---|
2549 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
2550 | {
|
---|
2551 |
|
---|
2552 | /*
|
---|
2553 | * If we're replacing existing timestamp signatures, remove old ones now.
|
---|
2554 | */
|
---|
2555 | if ( fReplaceExisting
|
---|
2556 | && RTCrPkcs7Attributes_IsPresent(&pSignerInfo->UnauthenticatedAttributes))
|
---|
2557 | {
|
---|
2558 | uint32_t iItem = pSignerInfo->UnauthenticatedAttributes.cItems;
|
---|
2559 | while (iItem-- > 0)
|
---|
2560 | {
|
---|
2561 | PRTCRPKCS7ATTRIBUTE pAttr = pSignerInfo->UnauthenticatedAttributes.papItems[iItem];
|
---|
2562 | if (pAttr->enmType == RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES) /* ASSUMES all counter sigs are timstamps */
|
---|
2563 | {
|
---|
2564 | if (cVerbosity > 1)
|
---|
2565 | RTMsgInfo("Removing counter signature in attribute #%u\n", iItem);
|
---|
2566 | rc = RTCrPkcs7Attributes_Erase(&pSignerInfo->UnauthenticatedAttributes, iItem);
|
---|
2567 | if (RT_FAILURE(rc))
|
---|
2568 | rcExit = RTMsgErrorExitFailure("RTCrPkcs7Attributes_Erase failed on #%u: %Rrc", iItem, rc);
|
---|
2569 | }
|
---|
2570 | }
|
---|
2571 | }
|
---|
2572 |
|
---|
2573 | /*
|
---|
2574 | * Add the new one.
|
---|
2575 | */
|
---|
2576 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
2577 | rcExit = SignToolPkcs7_AppendCounterSignature(pSignerInfo, pTsSignedData->SignerInfos.papItems[0], cVerbosity);
|
---|
2578 |
|
---|
2579 | /*
|
---|
2580 | * Make sure the signing certificate is included.
|
---|
2581 | */
|
---|
2582 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
2583 | {
|
---|
2584 | rcExit = SignToolPkcs7_AppendCertificate(pSignedData, pTimestampOpts->getRealCertificate());
|
---|
2585 |
|
---|
2586 | PCRTCRCERTCTX pInterCaCtx = NULL;
|
---|
2587 | while ((pInterCaCtx = pTimestampOpts->findNextIntermediateCert(pInterCaCtx)) != NULL)
|
---|
2588 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
2589 | rcExit = SignToolPkcs7_AppendCertificate(pSignedData, pInterCaCtx->pCert);
|
---|
2590 | }
|
---|
2591 |
|
---|
2592 | /*
|
---|
2593 | * Clean up.
|
---|
2594 | */
|
---|
2595 | RTCrPkcs7ContentInfo_Delete(&TsContentInfo);
|
---|
2596 | RTMemFree(pvSigned);
|
---|
2597 | }
|
---|
2598 | }
|
---|
2599 | RTCrPkcs7Attributes_Delete(&AuthAttribs);
|
---|
2600 | return rcExit;
|
---|
2601 | }
|
---|
2602 |
|
---|
2603 |
|
---|
2604 | static RTEXITCODE SignToolPkcs7_AddTimestampSignature(SIGNTOOLPKCS7EXE *pThis, unsigned cVerbosity, unsigned iSignature,
|
---|
2605 | bool fReplaceExisting, RTTIMESPEC SigningTime,
|
---|
2606 | SignToolTimestampOpts *pTimestampOpts)
|
---|
2607 | {
|
---|
2608 | /*
|
---|
2609 | * Locate the signature specified by iSignature and add a timestamp to it.
|
---|
2610 | */
|
---|
2611 | PRTCRPKCS7SIGNEDDATA pSignedData = NULL;
|
---|
2612 | PRTCRPKCS7SIGNERINFO pSignerInfo = SignToolPkcs7_FindNestedSignatureByIndex(pThis, iSignature, &pSignedData);
|
---|
2613 | if (!pSignerInfo)
|
---|
2614 | return RTMsgErrorExitFailure("No signature #%u in %s", iSignature, pThis->pszFilename);
|
---|
2615 |
|
---|
2616 | return SignToolPkcs7_AddTimestampSignatureEx(pSignerInfo, pSignedData, cVerbosity, fReplaceExisting,
|
---|
2617 | SigningTime, pTimestampOpts);
|
---|
2618 | }
|
---|
2619 |
|
---|
2620 |
|
---|
2621 | typedef enum SIGNDATATWEAK
|
---|
2622 | {
|
---|
2623 | kSignDataTweak_NoTweak = 1,
|
---|
2624 | kSignDataTweak_RootIsParent
|
---|
2625 | } SIGNDATATWEAK;
|
---|
2626 |
|
---|
2627 | static RTEXITCODE SignToolPkcs7_SignData(SIGNTOOLPKCS7 *pThis, PRTASN1CORE pToSignRoot, SIGNDATATWEAK enmTweak,
|
---|
2628 | const char *pszContentTypeId, unsigned cVerbosity, uint32_t fExtraFlags,
|
---|
2629 | RTDIGESTTYPE enmSigType, bool fReplaceExisting, bool fNoSigningTime,
|
---|
2630 | SignToolKeyPair *pSigningCertKey, RTCRSTORE hAddCerts,
|
---|
2631 | RTTIMESPEC SigningTime, size_t cTimestampOpts, SignToolTimestampOpts *paTimestampOpts)
|
---|
2632 | {
|
---|
2633 | /*
|
---|
2634 | * Encode it.
|
---|
2635 | */
|
---|
2636 | RTERRINFOSTATIC ErrInfo;
|
---|
2637 | uint32_t cbEncoded = 0;
|
---|
2638 | int rc = RTAsn1EncodePrepare(pToSignRoot, RTASN1ENCODE_F_DER, &cbEncoded, RTErrInfoInitStatic(&ErrInfo));
|
---|
2639 | if (RT_FAILURE(rc))
|
---|
2640 | return RTMsgErrorExitFailure("RTAsn1EncodePrepare failed: %Rrc%RTeim", rc, &ErrInfo.Core);
|
---|
2641 |
|
---|
2642 | if (cVerbosity >= 4)
|
---|
2643 | RTAsn1Dump(pToSignRoot, 0, 0, RTStrmDumpPrintfV, g_pStdOut);
|
---|
2644 |
|
---|
2645 | uint8_t *pbEncoded = (uint8_t *)RTMemTmpAllocZ(cbEncoded );
|
---|
2646 | if (!pbEncoded)
|
---|
2647 | return RTMsgErrorExitFailure("Failed to allocate %#z bytes for encoding data we're signing (%s)",
|
---|
2648 | cbEncoded, pszContentTypeId);
|
---|
2649 |
|
---|
2650 | RTEXITCODE rcExit = RTEXITCODE_FAILURE;
|
---|
2651 | rc = RTAsn1EncodeToBuffer(pToSignRoot, RTASN1ENCODE_F_DER, pbEncoded, cbEncoded, RTErrInfoInitStatic(&ErrInfo));
|
---|
2652 | if (RT_SUCCESS(rc))
|
---|
2653 | {
|
---|
2654 | size_t const cbToSign = cbEncoded - (enmTweak == kSignDataTweak_RootIsParent ? pToSignRoot->cbHdr : 0);
|
---|
2655 | void const *pvToSign = pbEncoded + (enmTweak == kSignDataTweak_RootIsParent ? pToSignRoot->cbHdr : 0);
|
---|
2656 |
|
---|
2657 | /*
|
---|
2658 | * Create additional authenticated attributes.
|
---|
2659 | */
|
---|
2660 | RTCRPKCS7ATTRIBUTES AuthAttribs;
|
---|
2661 | rc = RTCrPkcs7Attributes_Init(&AuthAttribs, &g_RTAsn1DefaultAllocator);
|
---|
2662 | if (RT_SUCCESS(rc))
|
---|
2663 | {
|
---|
2664 | rcExit = SignToolPkcs7_AddAuthAttribsForImageOrCatSignature(&AuthAttribs, SigningTime, fNoSigningTime,
|
---|
2665 | pszContentTypeId);
|
---|
2666 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
2667 | {
|
---|
2668 | /*
|
---|
2669 | * Ditch the old signature if so desired.
|
---|
2670 | * (It is okay to do this in the CAT case too, as we've already
|
---|
2671 | * encoded the data and won't touch pToSignRoot any more.)
|
---|
2672 | */
|
---|
2673 | pToSignRoot = NULL; /* (may become invalid if replacing) */
|
---|
2674 | if (fReplaceExisting && pThis->pSignedData)
|
---|
2675 | {
|
---|
2676 | RTCrPkcs7ContentInfo_Delete(&pThis->ContentInfo);
|
---|
2677 | pThis->pSignedData = NULL;
|
---|
2678 | RTMemFree(pThis->pbBuf);
|
---|
2679 | pThis->pbBuf = NULL;
|
---|
2680 | pThis->cbBuf = 0;
|
---|
2681 | }
|
---|
2682 |
|
---|
2683 | /*
|
---|
2684 | * Do the actual signing.
|
---|
2685 | */
|
---|
2686 | SIGNTOOLPKCS7 Src = { RTSIGNTOOLFILETYPE_DETECT, NULL, 0, NULL };
|
---|
2687 | PSIGNTOOLPKCS7 pSigDst = !pThis->pSignedData ? pThis : &Src;
|
---|
2688 | rcExit = SignToolPkcs7_Pkcs7SignStuff("image", pvToSign, cbToSign, &AuthAttribs, hAddCerts,
|
---|
2689 | fExtraFlags | RTCRPKCS7SIGN_SD_F_NO_DATA_ENCAP, enmSigType /** @todo ?? */,
|
---|
2690 | pSigningCertKey, cVerbosity,
|
---|
2691 | (void **)&pSigDst->pbBuf, &pSigDst->cbBuf,
|
---|
2692 | &pSigDst->ContentInfo, &pSigDst->pSignedData);
|
---|
2693 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
2694 | {
|
---|
2695 | /*
|
---|
2696 | * Add the requested timestamp signatures if requested.
|
---|
2697 | */
|
---|
2698 | for (size_t i = 0; rcExit == RTEXITCODE_SUCCESS &&i < cTimestampOpts; i++)
|
---|
2699 | if (paTimestampOpts[i].isComplete())
|
---|
2700 | rcExit = SignToolPkcs7_AddTimestampSignatureEx(pSigDst->pSignedData->SignerInfos.papItems[0],
|
---|
2701 | pSigDst->pSignedData,
|
---|
2702 | cVerbosity, false /*fReplaceExisting*/,
|
---|
2703 | SigningTime, &paTimestampOpts[i]);
|
---|
2704 |
|
---|
2705 | /*
|
---|
2706 | * Append the signature to the existing one, if that's what we're doing.
|
---|
2707 | */
|
---|
2708 | if (rcExit == RTEXITCODE_SUCCESS && pSigDst == &Src)
|
---|
2709 | rcExit = SignToolPkcs7_AddNestedSignature(pThis, &Src, cVerbosity, true /*fPrepend*/); /** @todo prepend/append option */
|
---|
2710 |
|
---|
2711 | /* cleanup */
|
---|
2712 | if (pSigDst == &Src)
|
---|
2713 | SignToolPkcs7_Delete(&Src);
|
---|
2714 | }
|
---|
2715 |
|
---|
2716 | }
|
---|
2717 | RTCrPkcs7Attributes_Delete(&AuthAttribs);
|
---|
2718 | }
|
---|
2719 | else
|
---|
2720 | RTMsgError("RTCrPkcs7SetOfAttributes_Init failed: %Rrc", rc);
|
---|
2721 | }
|
---|
2722 | else
|
---|
2723 | RTMsgError("RTAsn1EncodeToBuffer failed: %Rrc", rc);
|
---|
2724 | RTMemTmpFree(pbEncoded);
|
---|
2725 | return rcExit;
|
---|
2726 | }
|
---|
2727 |
|
---|
2728 |
|
---|
2729 | static RTEXITCODE SignToolPkcs7_SpcCompleteWithoutPageHashes(RTCRSPCINDIRECTDATACONTENT *pSpcIndData)
|
---|
2730 | {
|
---|
2731 | PCRTASN1ALLOCATORVTABLE const pAllocator = &g_RTAsn1DefaultAllocator;
|
---|
2732 | PRTCRSPCPEIMAGEDATA const pPeImage = pSpcIndData->Data.uValue.pPeImage;
|
---|
2733 | Assert(pPeImage);
|
---|
2734 |
|
---|
2735 | /*
|
---|
2736 | * Set it to File with an empty name.
|
---|
2737 | * RTCRSPCPEIMAGEDATA::Flags -vv
|
---|
2738 | * RTCRSPCPEIMAGEDATA::SeqCore -vv T0 -vv vv- pT2/CtxTag2
|
---|
2739 | * 0040: 04 01 82 37 02 01 0f 30-09 03 01 00 a0 04 a2 02 ...7...0........
|
---|
2740 | * 0050: 80 00 30 21 30 09 06 05-2b 0e 03 02 1a 05 00 04 ..0!0...+.......
|
---|
2741 | * ^^- pUcs2 / empty string
|
---|
2742 | */
|
---|
2743 |
|
---|
2744 | /* Create an empty BMP string. */
|
---|
2745 | RTASN1STRING EmptyStr;
|
---|
2746 | int rc = RTAsn1BmpString_Init(&EmptyStr, pAllocator);
|
---|
2747 | if (RT_FAILURE(rc))
|
---|
2748 | return RTMsgErrorExitFailure("RTAsn1BmpString_Init/Ucs2 failed: %Rrc", rc);
|
---|
2749 |
|
---|
2750 | /* Create an SPC string and use the above empty string with the Ucs2 setter. */
|
---|
2751 | RTEXITCODE rcExit = RTEXITCODE_FAILURE;
|
---|
2752 | RTCRSPCSTRING SpcString;
|
---|
2753 | rc = RTCrSpcString_Init(&SpcString, pAllocator);
|
---|
2754 | if (RT_SUCCESS(rc))
|
---|
2755 | {
|
---|
2756 | rc = RTCrSpcString_SetUcs2(&SpcString, &EmptyStr, pAllocator);
|
---|
2757 | if (RT_SUCCESS(rc))
|
---|
2758 | {
|
---|
2759 | /* Create a temporary SpcLink with the empty SpcString. */
|
---|
2760 | RTCRSPCLINK SpcLink;
|
---|
2761 | rc = RTCrSpcLink_Init(&SpcLink, pAllocator);
|
---|
2762 | if (RT_SUCCESS(rc))
|
---|
2763 | {
|
---|
2764 | /* Use the setter on the SpcLink object to copy the SpcString to it. */
|
---|
2765 | rc = RTCrSpcLink_SetFile(&SpcLink, &SpcString, pAllocator);
|
---|
2766 | if (RT_SUCCESS(rc))
|
---|
2767 | {
|
---|
2768 | /* Use the setter to copy SpcLink to the PeImage structure. */
|
---|
2769 | rc = RTCrSpcPeImageData_SetFile(pPeImage, &SpcLink, pAllocator);
|
---|
2770 | if (RT_SUCCESS(rc))
|
---|
2771 | rcExit = RTEXITCODE_SUCCESS;
|
---|
2772 | else
|
---|
2773 | RTMsgError("RTCrSpcPeImageData_SetFile failed: %Rrc", rc);
|
---|
2774 | }
|
---|
2775 | else
|
---|
2776 | RTMsgError("RTCrSpcLink_SetFile failed: %Rrc", rc);
|
---|
2777 | RTCrSpcLink_Delete(&SpcLink);
|
---|
2778 | }
|
---|
2779 | else
|
---|
2780 | RTMsgError("RTCrSpcLink_Init failed: %Rrc", rc);
|
---|
2781 | }
|
---|
2782 | else
|
---|
2783 | RTMsgError("RTCrSpcString_SetUcs2 failed: %Rrc", rc);
|
---|
2784 | RTCrSpcString_Delete(&SpcString);
|
---|
2785 | }
|
---|
2786 | else
|
---|
2787 | RTMsgError("RTCrSpcString_Init failed: %Rrc", rc);
|
---|
2788 | RTAsn1BmpString_Delete(&EmptyStr);
|
---|
2789 | return rcExit;
|
---|
2790 | }
|
---|
2791 |
|
---|
2792 |
|
---|
2793 | static RTEXITCODE SignToolPkcs7_SpcAddImagePageHashes(SIGNTOOLPKCS7EXE *pThis, RTCRSPCINDIRECTDATACONTENT *pSpcIndData,
|
---|
2794 | RTDIGESTTYPE enmSigType)
|
---|
2795 | {
|
---|
2796 | PCRTASN1ALLOCATORVTABLE const pAllocator = &g_RTAsn1DefaultAllocator;
|
---|
2797 | PRTCRSPCPEIMAGEDATA const pPeImage = pSpcIndData->Data.uValue.pPeImage;
|
---|
2798 | Assert(pPeImage);
|
---|
2799 |
|
---|
2800 | /*
|
---|
2801 | * The hashes are stored in the 'Moniker' attribute.
|
---|
2802 | */
|
---|
2803 | /* Create a temporary SpcLink with a default moniker. */
|
---|
2804 | RTCRSPCLINK SpcLink;
|
---|
2805 | int rc = RTCrSpcLink_Init(&SpcLink, pAllocator);
|
---|
2806 | if (RT_FAILURE(rc))
|
---|
2807 | return RTMsgErrorExitFailure("RTCrSpcLink_Init failed: %Rrc", rc);
|
---|
2808 | rc = RTCrSpcLink_SetMoniker(&SpcLink, NULL, pAllocator);
|
---|
2809 | if (RT_SUCCESS(rc))
|
---|
2810 | {
|
---|
2811 | /* Use the setter to copy SpcLink to the PeImage structure. */
|
---|
2812 | rc = RTCrSpcPeImageData_SetFile(pPeImage, &SpcLink, pAllocator);
|
---|
2813 | if (RT_FAILURE(rc))
|
---|
2814 | RTMsgError("RTCrSpcLink_SetFile failed: %Rrc", rc);
|
---|
2815 | }
|
---|
2816 | else
|
---|
2817 | RTMsgError("RTCrSpcLink_SetMoniker failed: %Rrc", rc);
|
---|
2818 | RTCrSpcLink_Delete(&SpcLink);
|
---|
2819 | if (RT_FAILURE(rc))
|
---|
2820 | return RTEXITCODE_FAILURE;
|
---|
2821 |
|
---|
2822 | /*
|
---|
2823 | * Now go to work on the moniker. It doesn't have any autogenerated
|
---|
2824 | * setters, so we must do stuff manually.
|
---|
2825 | */
|
---|
2826 | PRTCRSPCSERIALIZEDOBJECT pMoniker = pPeImage->T0.File.u.pMoniker;
|
---|
2827 | RTUUID Uuid;
|
---|
2828 | rc = RTUuidFromStr(&Uuid, RTCRSPCSERIALIZEDOBJECT_UUID_STR);
|
---|
2829 | if (RT_FAILURE(rc))
|
---|
2830 | return RTMsgErrorExitFailure("RTUuidFromStr failed: %Rrc", rc);
|
---|
2831 |
|
---|
2832 | rc = RTAsn1OctetString_AllocContent(&pMoniker->Uuid, &Uuid, sizeof(Uuid), pAllocator);
|
---|
2833 | if (RT_FAILURE(rc))
|
---|
2834 | return RTMsgErrorExitFailure("RTAsn1String_InitWithValue/UUID failed: %Rrc", rc);
|
---|
2835 |
|
---|
2836 | /* Create a new set of attributes and associate this with the SerializedData member. */
|
---|
2837 | PRTCRSPCSERIALIZEDOBJECTATTRIBUTES pSpcAttribs;
|
---|
2838 | rc = RTAsn1MemAllocZ(&pMoniker->SerializedData.EncapsulatedAllocation,
|
---|
2839 | (void **)&pSpcAttribs, sizeof(*pSpcAttribs));
|
---|
2840 | if (RT_FAILURE(rc))
|
---|
2841 | return RTMsgErrorExitFailure("RTAsn1MemAllocZ/pSpcAttribs failed: %Rrc", rc);
|
---|
2842 | pMoniker->SerializedData.pEncapsulated = RTCrSpcSerializedObjectAttributes_GetAsn1Core(pSpcAttribs);
|
---|
2843 | pMoniker->enmType = RTCRSPCSERIALIZEDOBJECTTYPE_ATTRIBUTES;
|
---|
2844 | pMoniker->u.pData = pSpcAttribs;
|
---|
2845 |
|
---|
2846 | rc = RTCrSpcSerializedObjectAttributes_Init(pSpcAttribs, pAllocator);
|
---|
2847 | if (RT_FAILURE(rc))
|
---|
2848 | return RTMsgErrorExitFailure("RTCrSpcSerializedObjectAttributes_Init failed: %Rrc", rc);
|
---|
2849 |
|
---|
2850 | /*
|
---|
2851 | * Add a single attribute to the set that we'll use for page hashes.
|
---|
2852 | */
|
---|
2853 | int32_t iPos = RTCrSpcSerializedObjectAttributes_Append(pSpcAttribs);
|
---|
2854 | if (iPos < 0)
|
---|
2855 | return RTMsgErrorExitFailure("RTCrSpcSerializedObjectAttributes_Append failed: %Rrc", iPos);
|
---|
2856 | PRTCRSPCSERIALIZEDOBJECTATTRIBUTE pSpcObjAttr = pSpcAttribs->papItems[iPos];
|
---|
2857 |
|
---|
2858 | if (enmSigType == RTDIGESTTYPE_SHA1)
|
---|
2859 | rc = RTCrSpcSerializedObjectAttribute_SetV1Hashes(pSpcObjAttr, NULL, pAllocator);
|
---|
2860 | else if (enmSigType == RTDIGESTTYPE_SHA256)
|
---|
2861 | rc = RTCrSpcSerializedObjectAttribute_SetV2Hashes(pSpcObjAttr, NULL, pAllocator);
|
---|
2862 | else
|
---|
2863 | rc = VERR_CR_DIGEST_NOT_SUPPORTED;
|
---|
2864 | if (RT_FAILURE(rc))
|
---|
2865 | return RTMsgErrorExitFailure("RTCrSpcSerializedObjectAttribute_SetV1Hashes/SetV2Hashes failed: %Rrc", rc);
|
---|
2866 | PRTCRSPCSERIALIZEDPAGEHASHES pSpcPageHashes = pSpcObjAttr->u.pPageHashes;
|
---|
2867 | Assert(pSpcPageHashes);
|
---|
2868 |
|
---|
2869 | /*
|
---|
2870 | * Now ask the loader for the number of pages in the page hash table
|
---|
2871 | * and calculate its size.
|
---|
2872 | */
|
---|
2873 | uint32_t cPages = 0;
|
---|
2874 | rc = RTLdrQueryPropEx(pThis->hLdrMod, RTLDRPROP_HASHABLE_PAGES, NULL, &cPages, sizeof(cPages), NULL);
|
---|
2875 | if (RT_FAILURE(rc))
|
---|
2876 | return RTMsgErrorExitFailure("RTLdrQueryPropEx/RTLDRPROP_HASHABLE_PAGES failed: %Rrc", rc);
|
---|
2877 |
|
---|
2878 | uint32_t const cbHash = RTCrDigestTypeToHashSize(enmSigType);
|
---|
2879 | AssertReturn(cbHash > 0, RTMsgErrorExitFailure("Invalid value: enmSigType=%d", enmSigType));
|
---|
2880 | uint32_t const cbTable = (sizeof(uint32_t) + cbHash) * cPages;
|
---|
2881 |
|
---|
2882 | /*
|
---|
2883 | * Allocate memory in the octect string.
|
---|
2884 | */
|
---|
2885 | rc = RTAsn1ContentAllocZ(&pSpcPageHashes->RawData.Asn1Core, cbTable, pAllocator);
|
---|
2886 | if (RT_FAILURE(rc))
|
---|
2887 | return RTMsgErrorExitFailure("RTAsn1ContentAllocZ failed to allocate %#x bytes for page hashes: %Rrc", cbTable, rc);
|
---|
2888 | pSpcPageHashes->pData = (PCRTCRSPCPEIMAGEPAGEHASHES)pSpcPageHashes->RawData.Asn1Core.uData.pu8;
|
---|
2889 |
|
---|
2890 | RTLDRPROP enmLdrProp;
|
---|
2891 | switch (enmSigType)
|
---|
2892 | {
|
---|
2893 | case RTDIGESTTYPE_SHA1: enmLdrProp = RTLDRPROP_SHA1_PAGE_HASHES; break;
|
---|
2894 | case RTDIGESTTYPE_SHA256: enmLdrProp = RTLDRPROP_SHA256_PAGE_HASHES; break;
|
---|
2895 | default: AssertFailedReturn(RTMsgErrorExitFailure("Invalid value: enmSigType=%d", enmSigType));
|
---|
2896 |
|
---|
2897 | }
|
---|
2898 | rc = RTLdrQueryPropEx(pThis->hLdrMod, enmLdrProp, NULL, (void *)pSpcPageHashes->RawData.Asn1Core.uData.pv, cbTable, NULL);
|
---|
2899 | if (RT_FAILURE(rc))
|
---|
2900 | return RTMsgErrorExitFailure("RTLdrQueryPropEx/RTLDRPROP_SHA?_PAGE_HASHES/%#x failed: %Rrc", cbTable, rc);
|
---|
2901 |
|
---|
2902 | return RTEXITCODE_SUCCESS;
|
---|
2903 | }
|
---|
2904 |
|
---|
2905 |
|
---|
2906 | static RTEXITCODE SignToolPkcs7_SpcAddImageHash(SIGNTOOLPKCS7EXE *pThis, RTCRSPCINDIRECTDATACONTENT *pSpcIndData,
|
---|
2907 | RTDIGESTTYPE enmSigType)
|
---|
2908 | {
|
---|
2909 | uint32_t const cbHash = RTCrDigestTypeToHashSize(enmSigType);
|
---|
2910 | const char * const pszAlgId = RTCrDigestTypeToAlgorithmOid(enmSigType);
|
---|
2911 |
|
---|
2912 | /*
|
---|
2913 | * Ask the loader for the hash.
|
---|
2914 | */
|
---|
2915 | uint8_t abHash[RTSHA512_HASH_SIZE];
|
---|
2916 | int rc = RTLdrHashImage(pThis->hLdrMod, enmSigType, abHash, sizeof(abHash));
|
---|
2917 | if (RT_FAILURE(rc))
|
---|
2918 | return RTMsgErrorExitFailure("RTLdrHashImage/%s failed: %Rrc", RTCrDigestTypeToName(enmSigType), rc);
|
---|
2919 |
|
---|
2920 | /*
|
---|
2921 | * Set it.
|
---|
2922 | */
|
---|
2923 | /** @todo no setter, this should be okay, though... */
|
---|
2924 | rc = RTAsn1ObjId_InitFromString(&pSpcIndData->DigestInfo.DigestAlgorithm.Algorithm, pszAlgId, &g_RTAsn1DefaultAllocator);
|
---|
2925 | if (RT_FAILURE(rc))
|
---|
2926 | return RTMsgErrorExitFailure("RTAsn1ObjId_InitFromString/%s failed: %Rrc", pszAlgId, rc);
|
---|
2927 | RTAsn1DynType_SetToNull(&pSpcIndData->DigestInfo.DigestAlgorithm.Parameters); /* ASSUMES RSA or similar */
|
---|
2928 |
|
---|
2929 | rc = RTAsn1ContentDup(&pSpcIndData->DigestInfo.Digest.Asn1Core, abHash, cbHash, &g_RTAsn1DefaultAllocator);
|
---|
2930 | if (RT_FAILURE(rc))
|
---|
2931 | return RTMsgErrorExitFailure("RTAsn1ContentDup/%#x failed: %Rrc", cbHash, rc);
|
---|
2932 |
|
---|
2933 | return RTEXITCODE_SUCCESS;
|
---|
2934 | }
|
---|
2935 |
|
---|
2936 |
|
---|
2937 | static RTEXITCODE SignToolPkcs7_AddOrReplaceSignature(SIGNTOOLPKCS7EXE *pThis, unsigned cVerbosity, RTDIGESTTYPE enmSigType,
|
---|
2938 | bool fReplaceExisting, bool fHashPages, bool fNoSigningTime,
|
---|
2939 | SignToolKeyPair *pSigningCertKey, RTCRSTORE hAddCerts,
|
---|
2940 | RTTIMESPEC SigningTime,
|
---|
2941 | size_t cTimestampOpts, SignToolTimestampOpts *paTimestampOpts)
|
---|
2942 | {
|
---|
2943 | /*
|
---|
2944 | * We must construct the data to be packed into the PKCS#7 signature
|
---|
2945 | * and signed.
|
---|
2946 | */
|
---|
2947 | PCRTASN1ALLOCATORVTABLE const pAllocator = &g_RTAsn1DefaultAllocator;
|
---|
2948 | RTCRSPCINDIRECTDATACONTENT SpcIndData;
|
---|
2949 | int rc = RTCrSpcIndirectDataContent_Init(&SpcIndData, pAllocator);
|
---|
2950 | if (RT_FAILURE(rc))
|
---|
2951 | return RTMsgErrorExitFailure("RTCrSpcIndirectDataContent_Init failed: %Rrc", rc);
|
---|
2952 |
|
---|
2953 | /* Set the data to PE image. */
|
---|
2954 | /** @todo Generalize the Type + enmType DYN stuff and generate setters. */
|
---|
2955 | Assert(SpcIndData.Data.enmType == RTCRSPCAAOVTYPE_NOT_PRESENT);
|
---|
2956 | Assert(SpcIndData.Data.uValue.pPeImage == NULL);
|
---|
2957 | RTEXITCODE rcExit;
|
---|
2958 | rc = RTAsn1ObjId_SetFromString(&SpcIndData.Data.Type, RTCRSPCPEIMAGEDATA_OID, pAllocator);
|
---|
2959 | if (RT_SUCCESS(rc))
|
---|
2960 | {
|
---|
2961 | SpcIndData.Data.enmType = RTCRSPCAAOVTYPE_PE_IMAGE_DATA;
|
---|
2962 | rc = RTAsn1MemAllocZ(&SpcIndData.Data.Allocation, (void **)&SpcIndData.Data.uValue.pPeImage,
|
---|
2963 | sizeof(*SpcIndData.Data.uValue.pPeImage));
|
---|
2964 | if (RT_SUCCESS(rc))
|
---|
2965 | {
|
---|
2966 | rc = RTCrSpcPeImageData_Init(SpcIndData.Data.uValue.pPeImage, pAllocator);
|
---|
2967 | if (RT_SUCCESS(rc))
|
---|
2968 | {
|
---|
2969 | /* Old (SHA1) signatures has a Flags member, it's zero bits, though. */
|
---|
2970 | if (enmSigType == RTDIGESTTYPE_SHA1)
|
---|
2971 | {
|
---|
2972 | uint8_t bFlags = 0;
|
---|
2973 | RTASN1BITSTRING Flags;
|
---|
2974 | rc = RTAsn1BitString_InitWithData(&Flags, &bFlags, 0, pAllocator);
|
---|
2975 | if (RT_SUCCESS(rc))
|
---|
2976 | {
|
---|
2977 | rc = RTCrSpcPeImageData_SetFlags(SpcIndData.Data.uValue.pPeImage, &Flags, pAllocator);
|
---|
2978 | RTAsn1BitString_Delete(&Flags);
|
---|
2979 | if (RT_FAILURE(rc))
|
---|
2980 | rcExit = RTMsgErrorExitFailure("RTCrSpcPeImageData_SetFlags failed: %Rrc", rc);
|
---|
2981 | }
|
---|
2982 | else
|
---|
2983 | rcExit = RTMsgErrorExitFailure("RTAsn1BitString_InitWithData failed: %Rrc", rc);
|
---|
2984 | }
|
---|
2985 |
|
---|
2986 | /*
|
---|
2987 | * Add the hashes.
|
---|
2988 | */
|
---|
2989 | rcExit = SignToolPkcs7_SpcAddImageHash(pThis, &SpcIndData, enmSigType);
|
---|
2990 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
2991 | {
|
---|
2992 | if (fHashPages)
|
---|
2993 | rcExit = SignToolPkcs7_SpcAddImagePageHashes(pThis, &SpcIndData, enmSigType);
|
---|
2994 | else
|
---|
2995 | rcExit = SignToolPkcs7_SpcCompleteWithoutPageHashes(&SpcIndData);
|
---|
2996 |
|
---|
2997 | /*
|
---|
2998 | * Encode and sign the SPC data, timestamp it, and line it up for adding to the executable.
|
---|
2999 | */
|
---|
3000 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
3001 | rcExit = SignToolPkcs7_SignData(pThis, RTCrSpcIndirectDataContent_GetAsn1Core(&SpcIndData),
|
---|
3002 | kSignDataTweak_NoTweak, RTCRSPCINDIRECTDATACONTENT_OID, cVerbosity, 0,
|
---|
3003 | enmSigType, fReplaceExisting, fNoSigningTime, pSigningCertKey, hAddCerts,
|
---|
3004 | SigningTime, cTimestampOpts, paTimestampOpts);
|
---|
3005 | }
|
---|
3006 | }
|
---|
3007 | else
|
---|
3008 | rcExit = RTMsgErrorExitFailure("RTCrPkcs7SignerInfos_Init failed: %Rrc", rc);
|
---|
3009 | }
|
---|
3010 | else
|
---|
3011 | rcExit = RTMsgErrorExitFailure("RTAsn1MemAllocZ failed for RTCRSPCPEIMAGEDATA: %Rrc", rc);
|
---|
3012 | }
|
---|
3013 | else
|
---|
3014 | rcExit = RTMsgErrorExitFailure("RTAsn1ObjId_SetWithString/SpcPeImageData failed: %Rrc", rc);
|
---|
3015 |
|
---|
3016 | RTCrSpcIndirectDataContent_Delete(&SpcIndData);
|
---|
3017 | return rcExit;
|
---|
3018 | }
|
---|
3019 |
|
---|
3020 |
|
---|
3021 | static RTEXITCODE SignToolPkcs7_AddOrReplaceCatSignature(SIGNTOOLPKCS7 *pThis, unsigned cVerbosity, RTDIGESTTYPE enmSigType,
|
---|
3022 | bool fReplaceExisting, bool fNoSigningTime,
|
---|
3023 | SignToolKeyPair *pSigningCertKey, RTCRSTORE hAddCerts,
|
---|
3024 | RTTIMESPEC SigningTime,
|
---|
3025 | size_t cTimestampOpts, SignToolTimestampOpts *paTimestampOpts)
|
---|
3026 | {
|
---|
3027 | AssertReturn(pThis->pSignedData, RTMsgErrorExitFailure("pSignedData is NULL!"));
|
---|
3028 |
|
---|
3029 | /*
|
---|
3030 | * Figure out what to sign first.
|
---|
3031 | */
|
---|
3032 | uint32_t fExtraFlags = 0;
|
---|
3033 | PRTASN1CORE pToSign = &pThis->pSignedData->ContentInfo.Content.Asn1Core;
|
---|
3034 | const char *pszType = pThis->pSignedData->ContentInfo.ContentType.szObjId;
|
---|
3035 |
|
---|
3036 | if (!fReplaceExisting && pThis->pSignedData->SignerInfos.cItems == 0)
|
---|
3037 | fReplaceExisting = true;
|
---|
3038 | if (!fReplaceExisting)
|
---|
3039 | {
|
---|
3040 | pszType = RTCR_PKCS7_DATA_OID;
|
---|
3041 | fExtraFlags |= RTCRPKCS7SIGN_SD_F_DEATCHED;
|
---|
3042 | }
|
---|
3043 |
|
---|
3044 | /*
|
---|
3045 | * Do the signing.
|
---|
3046 | */
|
---|
3047 | RTEXITCODE rcExit = SignToolPkcs7_SignData(pThis, pToSign, kSignDataTweak_RootIsParent,
|
---|
3048 | pszType, cVerbosity, fExtraFlags, enmSigType, fReplaceExisting,
|
---|
3049 | fNoSigningTime, pSigningCertKey, hAddCerts,
|
---|
3050 | SigningTime, cTimestampOpts, paTimestampOpts);
|
---|
3051 |
|
---|
3052 | /* probably need to clean up stuff related to nested signatures here later... */
|
---|
3053 | return rcExit;
|
---|
3054 | }
|
---|
3055 |
|
---|
3056 | #endif /* !IPRT_SIGNTOOL_NO_SIGNING */
|
---|
3057 |
|
---|
3058 |
|
---|
3059 | /*********************************************************************************************************************************
|
---|
3060 | * Option handlers shared by 'sign-exe', 'sign-cat', 'add-timestamp-exe-signature' and others. *
|
---|
3061 | *********************************************************************************************************************************/
|
---|
3062 | #ifndef IPRT_SIGNTOOL_NO_SIGNING
|
---|
3063 |
|
---|
3064 | static RTEXITCODE HandleOptAddCert(PRTCRSTORE phStore, const char *pszFile)
|
---|
3065 | {
|
---|
3066 | if (*phStore == NIL_RTCRSTORE)
|
---|
3067 | {
|
---|
3068 | int rc = RTCrStoreCreateInMem(phStore, 2);
|
---|
3069 | if (RT_FAILURE(rc))
|
---|
3070 | return RTMsgErrorExitFailure("RTCrStoreCreateInMem(,2) failed: %Rrc", rc);
|
---|
3071 | }
|
---|
3072 | RTERRINFOSTATIC ErrInfo;
|
---|
3073 | int rc = RTCrStoreCertAddFromFile(*phStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND, pszFile, RTErrInfoInitStatic(&ErrInfo));
|
---|
3074 | if (RT_FAILURE(rc))
|
---|
3075 | return RTMsgErrorExitFailure("Error reading certificate from '%s': %Rrc%#RTeim", pszFile, rc, &ErrInfo.Core);
|
---|
3076 | return RTEXITCODE_SUCCESS;
|
---|
3077 | }
|
---|
3078 |
|
---|
3079 | static RTEXITCODE HandleOptSignatureType(RTDIGESTTYPE *penmSigType, const char *pszType)
|
---|
3080 | {
|
---|
3081 | if ( RTStrICmpAscii(pszType, "sha1") == 0
|
---|
3082 | || RTStrICmpAscii(pszType, "sha-1") == 0)
|
---|
3083 | *penmSigType = RTDIGESTTYPE_SHA1;
|
---|
3084 | else if ( RTStrICmpAscii(pszType, "sha256") == 0
|
---|
3085 | || RTStrICmpAscii(pszType, "sha-256") == 0)
|
---|
3086 | *penmSigType = RTDIGESTTYPE_SHA256;
|
---|
3087 | else
|
---|
3088 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown signature type: %s (expected sha1 or sha256)", pszType);
|
---|
3089 | return RTEXITCODE_SUCCESS;
|
---|
3090 | }
|
---|
3091 |
|
---|
3092 |
|
---|
3093 | static RTEXITCODE HandleOptTimestampType(SignToolTimestampOpts *pTimestampOpts, const char *pszType)
|
---|
3094 | {
|
---|
3095 | if (strcmp(pszType, "old") == 0)
|
---|
3096 | pTimestampOpts->m_enmType = kTimestampType_Old;
|
---|
3097 | else if (strcmp(pszType, "new") == 0)
|
---|
3098 | pTimestampOpts->m_enmType = kTimestampType_New;
|
---|
3099 | else
|
---|
3100 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown timestamp type: %s", pszType);
|
---|
3101 | return RTEXITCODE_SUCCESS;
|
---|
3102 | }
|
---|
3103 |
|
---|
3104 | static RTEXITCODE HandleOptTimestampOverride(PRTTIMESPEC pSigningTime, const char *pszPartialTs)
|
---|
3105 | {
|
---|
3106 | /*
|
---|
3107 | * First try use it as-is.
|
---|
3108 | */
|
---|
3109 | if (RTTimeSpecFromString(pSigningTime, pszPartialTs) != NULL)
|
---|
3110 | return RTEXITCODE_SUCCESS;
|
---|
3111 |
|
---|
3112 | /* Check the input against a pattern, making sure we've got something that
|
---|
3113 | makes sense before trying to merge. */
|
---|
3114 | size_t const cchPartialTs = strlen(pszPartialTs);
|
---|
3115 | static char s_szPattern[] = "0000-00-00T00:00:";
|
---|
3116 | if (cchPartialTs > sizeof(s_szPattern) - 1) /* It is not a partial timestamp if we've got the seconds component. */
|
---|
3117 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp: %s", pszPartialTs);
|
---|
3118 |
|
---|
3119 | for (size_t off = 0; off < cchPartialTs; off++)
|
---|
3120 | switch (s_szPattern[off])
|
---|
3121 | {
|
---|
3122 | case '0':
|
---|
3123 | if (!RT_C_IS_DIGIT(pszPartialTs[off]))
|
---|
3124 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp, expected digit at position %u: %s",
|
---|
3125 | off + 1, pszPartialTs);
|
---|
3126 | break;
|
---|
3127 | case '-':
|
---|
3128 | case ':':
|
---|
3129 | if (pszPartialTs[off] != s_szPattern[off])
|
---|
3130 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp, expected '%c' at position %u: %s",
|
---|
3131 | s_szPattern[off], off + 1, pszPartialTs);
|
---|
3132 | break;
|
---|
3133 | case 'T':
|
---|
3134 | if ( pszPartialTs[off] != 'T'
|
---|
3135 | && pszPartialTs[off] != 't'
|
---|
3136 | && pszPartialTs[off] != ' ')
|
---|
3137 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp, expected 'T' or space at position %u: %s",
|
---|
3138 | off + 1, pszPartialTs);
|
---|
3139 | break;
|
---|
3140 | default:
|
---|
3141 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Internal error");
|
---|
3142 | }
|
---|
3143 |
|
---|
3144 | if (RT_C_IS_DIGIT(s_szPattern[cchPartialTs]) && RT_C_IS_DIGIT(s_szPattern[cchPartialTs - 1]))
|
---|
3145 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Incomplete timstamp component: %s", pszPartialTs);
|
---|
3146 |
|
---|
3147 | /*
|
---|
3148 | * Take the current time and merge in the components from pszPartialTs.
|
---|
3149 | */
|
---|
3150 | char szSigningTime[RTTIME_STR_LEN];
|
---|
3151 | RTTIMESPEC Now;
|
---|
3152 | RTTimeSpecToString(RTTimeNow(&Now), szSigningTime, sizeof(szSigningTime));
|
---|
3153 | memcpy(szSigningTime, pszPartialTs, cchPartialTs);
|
---|
3154 | szSigningTime[4+1+2+1+2] = 'T';
|
---|
3155 |
|
---|
3156 | /* Fix 29th for non-leap override: */
|
---|
3157 | if (memcmp(&szSigningTime[5], RT_STR_TUPLE("02-29")) == 0)
|
---|
3158 | {
|
---|
3159 | if (!RTTimeIsLeapYear(RTStrToUInt32(szSigningTime)))
|
---|
3160 | szSigningTime[9] = '8';
|
---|
3161 | }
|
---|
3162 | if (RTTimeSpecFromString(pSigningTime, szSigningTime) == NULL)
|
---|
3163 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid timestamp: %s (%s)", pszPartialTs, szSigningTime);
|
---|
3164 |
|
---|
3165 | return RTEXITCODE_SUCCESS;
|
---|
3166 | }
|
---|
3167 |
|
---|
3168 | static RTEXITCODE HandleOptFileType(RTSIGNTOOLFILETYPE *penmFileType, const char *pszType)
|
---|
3169 | {
|
---|
3170 | if (strcmp(pszType, "detect") == 0 || strcmp(pszType, "auto") == 0)
|
---|
3171 | *penmFileType = RTSIGNTOOLFILETYPE_DETECT;
|
---|
3172 | else if (strcmp(pszType, "exe") == 0)
|
---|
3173 | *penmFileType = RTSIGNTOOLFILETYPE_EXE;
|
---|
3174 | else if (strcmp(pszType, "cat") == 0)
|
---|
3175 | *penmFileType = RTSIGNTOOLFILETYPE_CAT;
|
---|
3176 | else
|
---|
3177 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown forced file type: %s", pszType);
|
---|
3178 | return RTEXITCODE_SUCCESS;
|
---|
3179 | }
|
---|
3180 |
|
---|
3181 | #endif /* !IPRT_SIGNTOOL_NO_SIGNING */
|
---|
3182 |
|
---|
3183 | /**
|
---|
3184 | * Detects the type of files @a pszFile is (by reading from it).
|
---|
3185 | *
|
---|
3186 | * @returns The file type, or RTSIGNTOOLFILETYPE_UNKNOWN (error displayed).
|
---|
3187 | * @param enmForceFileType Usually set to RTSIGNTOOLFILETYPE_DETECT, but if
|
---|
3188 | * not we'll return this without probing the file.
|
---|
3189 | * @param pszFile The name of the file to detect the type of.
|
---|
3190 | */
|
---|
3191 | static RTSIGNTOOLFILETYPE DetectFileType(RTSIGNTOOLFILETYPE enmForceFileType, const char *pszFile)
|
---|
3192 | {
|
---|
3193 | /*
|
---|
3194 | * Forced?
|
---|
3195 | */
|
---|
3196 | if (enmForceFileType != RTSIGNTOOLFILETYPE_DETECT)
|
---|
3197 | return enmForceFileType;
|
---|
3198 |
|
---|
3199 | /*
|
---|
3200 | * Read the start of the file.
|
---|
3201 | */
|
---|
3202 | RTFILE hFile = NIL_RTFILE;
|
---|
3203 | int rc = RTFileOpen(&hFile, pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_WRITE);
|
---|
3204 | if (RT_FAILURE(rc))
|
---|
3205 | {
|
---|
3206 | RTMsgError("Error opening '%s' for reading: %Rrc", pszFile, rc);
|
---|
3207 | return RTSIGNTOOLFILETYPE_UNKNOWN;
|
---|
3208 | }
|
---|
3209 |
|
---|
3210 | union
|
---|
3211 | {
|
---|
3212 | uint8_t ab[256];
|
---|
3213 | uint16_t au16[256/2];
|
---|
3214 | uint32_t au32[256/4];
|
---|
3215 | } uBuf;
|
---|
3216 | RT_ZERO(uBuf);
|
---|
3217 |
|
---|
3218 | size_t cbRead = 0;
|
---|
3219 | rc = RTFileRead(hFile, &uBuf, sizeof(uBuf), &cbRead);
|
---|
3220 | if (RT_FAILURE(rc))
|
---|
3221 | RTMsgError("Error reading from '%s': %Rrc", pszFile, rc);
|
---|
3222 |
|
---|
3223 | uint64_t cbFile;
|
---|
3224 | int rcSize = RTFileQuerySize(hFile, &cbFile);
|
---|
3225 | if (RT_FAILURE(rcSize))
|
---|
3226 | RTMsgError("Error querying size of '%s': %Rrc", pszFile, rc);
|
---|
3227 |
|
---|
3228 | RTFileClose(hFile);
|
---|
3229 | if (RT_FAILURE(rc) || RT_FAILURE(rcSize))
|
---|
3230 | return RTSIGNTOOLFILETYPE_UNKNOWN;
|
---|
3231 |
|
---|
3232 | /*
|
---|
3233 | * Try guess the kind of file.
|
---|
3234 | */
|
---|
3235 | /* All the executable magics we know: */
|
---|
3236 | if ( uBuf.au16[0] == RT_H2LE_U16_C(IMAGE_DOS_SIGNATURE)
|
---|
3237 | || uBuf.au16[0] == RT_H2LE_U16_C(IMAGE_NE_SIGNATURE)
|
---|
3238 | || uBuf.au16[0] == RT_H2LE_U16_C(IMAGE_LX_SIGNATURE)
|
---|
3239 | || uBuf.au16[0] == RT_H2LE_U16_C(IMAGE_LE_SIGNATURE)
|
---|
3240 | || uBuf.au32[0] == RT_H2LE_U32_C(IMAGE_NT_SIGNATURE)
|
---|
3241 | || uBuf.au32[0] == RT_H2LE_U32_C(IMAGE_ELF_SIGNATURE)
|
---|
3242 | || uBuf.au32[0] == IMAGE_FAT_SIGNATURE
|
---|
3243 | || uBuf.au32[0] == IMAGE_FAT_SIGNATURE_OE
|
---|
3244 | || uBuf.au32[0] == IMAGE_MACHO32_SIGNATURE
|
---|
3245 | || uBuf.au32[0] == IMAGE_MACHO32_SIGNATURE_OE
|
---|
3246 | || uBuf.au32[0] == IMAGE_MACHO64_SIGNATURE
|
---|
3247 | || uBuf.au32[0] == IMAGE_MACHO64_SIGNATURE_OE)
|
---|
3248 | return RTSIGNTOOLFILETYPE_EXE;
|
---|
3249 |
|
---|
3250 | /*
|
---|
3251 | * Catalog files are PKCS#7 SignedData and starts with a ContentInfo, i.e.:
|
---|
3252 | * SEQUENCE {
|
---|
3253 | * contentType OBJECT IDENTIFIER,
|
---|
3254 | * content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL
|
---|
3255 | * }
|
---|
3256 | *
|
---|
3257 | * We ASSUME that it's DER encoded and doesn't use an indefinite length form
|
---|
3258 | * at the start and that contentType is signedData (1.2.840.113549.1.7.2).
|
---|
3259 | *
|
---|
3260 | * Example of a 10353 (0x2871) byte long file:
|
---|
3261 | * vv-------- contentType -------vv
|
---|
3262 | * 00000000 30 82 28 6D 06 09 2A 86 48 86 F7 0D 01 07 02 A0
|
---|
3263 | * 00000010 82 28 5E 30 82 28 5A 02 01 01 31 0B 30 09 06 05
|
---|
3264 | */
|
---|
3265 | if ( uBuf.ab[0] == (ASN1_TAG_SEQUENCE | ASN1_TAGFLAG_CONSTRUCTED)
|
---|
3266 | && uBuf.ab[1] != 0x80 /* not indefinite form */
|
---|
3267 | && uBuf.ab[1] > 0x30)
|
---|
3268 | {
|
---|
3269 | size_t off = 1;
|
---|
3270 | uint32_t cbRec = uBuf.ab[1];
|
---|
3271 | if (cbRec & 0x80)
|
---|
3272 | {
|
---|
3273 | cbRec &= 0x7f;
|
---|
3274 | off += cbRec;
|
---|
3275 | switch (cbRec)
|
---|
3276 | {
|
---|
3277 | case 1: cbRec = uBuf.ab[2]; break;
|
---|
3278 | case 2: cbRec = RT_MAKE_U16( uBuf.ab[3], uBuf.ab[2]); break;
|
---|
3279 | case 3: cbRec = RT_MAKE_U32_FROM_U8(uBuf.ab[4], uBuf.ab[3], uBuf.ab[2], 0); break;
|
---|
3280 | case 4: cbRec = RT_MAKE_U32_FROM_U8(uBuf.ab[5], uBuf.ab[4], uBuf.ab[3], uBuf.ab[2]); break;
|
---|
3281 | default: cbRec = UINT32_MAX; break;
|
---|
3282 | }
|
---|
3283 | }
|
---|
3284 | if (off <= 5)
|
---|
3285 | {
|
---|
3286 | off++;
|
---|
3287 | if (off + cbRec == cbFile)
|
---|
3288 | {
|
---|
3289 | /* If the contentType is signedData we're going to treat it as a catalog file,
|
---|
3290 | we don't currently much care about the signed content of a cat file. */
|
---|
3291 | static const uint8_t s_abSignedDataOid[] =
|
---|
3292 | { ASN1_TAG_OID, 9 /*length*/, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x07, 0x02 };
|
---|
3293 | if (memcmp(&uBuf.ab[off], s_abSignedDataOid, sizeof(s_abSignedDataOid)) == 0)
|
---|
3294 | return RTSIGNTOOLFILETYPE_CAT;
|
---|
3295 | }
|
---|
3296 | }
|
---|
3297 | }
|
---|
3298 |
|
---|
3299 | RTMsgError("Unable to detect type of '%s'", pszFile);
|
---|
3300 | return RTSIGNTOOLFILETYPE_UNKNOWN;
|
---|
3301 | }
|
---|
3302 |
|
---|
3303 |
|
---|
3304 | /*********************************************************************************************************************************
|
---|
3305 | * The 'extract-exe-signer-cert' command. *
|
---|
3306 | *********************************************************************************************************************************/
|
---|
3307 |
|
---|
3308 | static RTEXITCODE HelpExtractExeSignerCert(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
3309 | {
|
---|
3310 | RT_NOREF_PV(enmLevel);
|
---|
3311 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
3312 | "extract-exe-signer-cert [--as-c-array=name|--ber|--cer|--der] [--signature-index|-i <num>] [--input|--exe|-e] <exe> [--output|-o] <outfile.cer/h>\n");
|
---|
3313 | return RTEXITCODE_SUCCESS;
|
---|
3314 | }
|
---|
3315 |
|
---|
3316 | static RTEXITCODE WriteCertToFile(PCRTCRX509CERTIFICATE pCert, const char *pszFilename, bool fForce)
|
---|
3317 | {
|
---|
3318 | RTEXITCODE rcExit = RTEXITCODE_FAILURE;
|
---|
3319 | RTFILE hFile;
|
---|
3320 | int rc = RTFileOpen(&hFile, pszFilename,
|
---|
3321 | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | (fForce ? RTFILE_O_CREATE_REPLACE : RTFILE_O_CREATE));
|
---|
3322 | if (RT_SUCCESS(rc))
|
---|
3323 | {
|
---|
3324 | uint32_t cbCert = pCert->SeqCore.Asn1Core.cbHdr + pCert->SeqCore.Asn1Core.cb;
|
---|
3325 | rc = RTFileWrite(hFile, pCert->SeqCore.Asn1Core.uData.pu8 - pCert->SeqCore.Asn1Core.cbHdr,
|
---|
3326 | cbCert, NULL);
|
---|
3327 | if (RT_SUCCESS(rc))
|
---|
3328 | {
|
---|
3329 | rc = RTFileClose(hFile);
|
---|
3330 | if (RT_SUCCESS(rc))
|
---|
3331 | {
|
---|
3332 | hFile = NIL_RTFILE;
|
---|
3333 | rcExit = RTEXITCODE_SUCCESS;
|
---|
3334 | RTMsgInfo("Successfully wrote %u bytes to '%s'", cbCert, pszFilename);
|
---|
3335 | }
|
---|
3336 | else
|
---|
3337 | RTMsgError("RTFileClose failed: %Rrc", rc);
|
---|
3338 | }
|
---|
3339 | else
|
---|
3340 | RTMsgError("RTFileWrite failed: %Rrc", rc);
|
---|
3341 | RTFileClose(hFile);
|
---|
3342 | }
|
---|
3343 | else
|
---|
3344 | RTMsgError("Error opening '%s' for writing: %Rrc", pszFilename, rc);
|
---|
3345 | return rcExit;
|
---|
3346 | }
|
---|
3347 |
|
---|
3348 |
|
---|
3349 | static void PrintCertAsCArray(PCRTCRX509CERTIFICATE pCert, uint32_t iSignature, const char *pszBaseNm, PRTSTREAM pStrm)
|
---|
3350 | {
|
---|
3351 | uint32_t const cbCert = pCert->SeqCore.Asn1Core.cbHdr + pCert->SeqCore.Asn1Core.cb;
|
---|
3352 | uint8_t const * const pbCert = pCert->SeqCore.Asn1Core.uData.pu8 - pCert->SeqCore.Asn1Core.cbHdr;
|
---|
3353 | if (iSignature == UINT32_MAX)
|
---|
3354 | RTStrmPrintf(pStrm,
|
---|
3355 | "uint32_t const g_cb%s = %u;\n"
|
---|
3356 | "uint8_t const g_ab%s[%u] =\n"
|
---|
3357 | "{",
|
---|
3358 | pszBaseNm, cbCert, pszBaseNm, cbCert);
|
---|
3359 | else
|
---|
3360 | RTStrmPrintf(pStrm, "static uint8_t const g_ab%sCert%u[%u] =\n{", pszBaseNm, iSignature, cbCert);
|
---|
3361 | for (uint32_t off = 0; off < cbCert; off++)
|
---|
3362 | {
|
---|
3363 | if (off % 16 == 0)
|
---|
3364 | RTStrmPrintf(pStrm, "\n ");
|
---|
3365 | RTStrmPrintf(pStrm, " %#04x,", pbCert[off]);
|
---|
3366 | }
|
---|
3367 | RTStrmPrintf(pStrm, "\n};\n\n");
|
---|
3368 | }
|
---|
3369 |
|
---|
3370 |
|
---|
3371 | static void PrintCertTableAsC(uint32_t cSignatures, const char *pszBaseNm, PRTSTREAM pStrm)
|
---|
3372 | {
|
---|
3373 | RTStrmPrintf(pStrm,
|
---|
3374 | "uint32_t const g_c%s = %u;\n"
|
---|
3375 | "struct { uint8_t const *pbCert; size_t cbCert; } const g_a%s[%u] =\n"
|
---|
3376 | "{\n"
|
---|
3377 | , pszBaseNm, cSignatures, pszBaseNm, cSignatures ? cSignatures : 1);
|
---|
3378 | for (uint32_t iSignature = 0; iSignature < cSignatures; iSignature++)
|
---|
3379 | RTStrmPrintf(pStrm, " { g_ab%sCert%u, sizeof(g_ab%sCert%u) },\n",
|
---|
3380 | pszBaseNm, iSignature, pszBaseNm, iSignature);
|
---|
3381 | if (!cSignatures)
|
---|
3382 | RTStrmPrintf(pStrm, " { NULL, 0 } /* dummy */ \n");
|
---|
3383 | RTStrmPrintf(pStrm, "};\n");
|
---|
3384 | }
|
---|
3385 |
|
---|
3386 |
|
---|
3387 | static RTEXITCODE WriteCertToFileAsC(PCRTCRX509CERTIFICATE pCert, const char *pszFilename, bool fForce, const char *pszBaseNm)
|
---|
3388 | {
|
---|
3389 | RTEXITCODE rcExit;
|
---|
3390 | PRTSTREAM pStrm = NULL;
|
---|
3391 | int rc = RTStrmOpen(pszFilename, fForce ? "wt+" : "wtx", &pStrm);
|
---|
3392 | if (RT_SUCCESS(rc))
|
---|
3393 | {
|
---|
3394 | PrintCertAsCArray(pCert, UINT32_MAX, pszBaseNm, pStrm);
|
---|
3395 | rc = RTStrmClose(pStrm);
|
---|
3396 | if (RT_SUCCESS(rc))
|
---|
3397 | rcExit = RTEXITCODE_SUCCESS;
|
---|
3398 | else
|
---|
3399 | rcExit = RTMsgErrorExitFailure("Error writing/closing '%s': %Rrc", pszFilename, rc);
|
---|
3400 | }
|
---|
3401 | else
|
---|
3402 | rcExit = RTMsgErrorExitFailure("Failed to open '%s' for writing: %Rrc", pszFilename, rc);
|
---|
3403 | return rcExit;
|
---|
3404 | }
|
---|
3405 |
|
---|
3406 |
|
---|
3407 |
|
---|
3408 | static RTEXITCODE HandleExtractExeSignerCert(int cArgs, char **papszArgs)
|
---|
3409 | {
|
---|
3410 | /*
|
---|
3411 | * Parse arguments.
|
---|
3412 | */
|
---|
3413 | static const RTGETOPTDEF s_aOptions[] =
|
---|
3414 | {
|
---|
3415 | { "--ber", 'b', RTGETOPT_REQ_NOTHING },
|
---|
3416 | { "--cer", 'c', RTGETOPT_REQ_NOTHING },
|
---|
3417 | { "--der", 'd', RTGETOPT_REQ_NOTHING },
|
---|
3418 | { "--exe", 'e', RTGETOPT_REQ_STRING },
|
---|
3419 | { "--input", 'e', RTGETOPT_REQ_STRING },
|
---|
3420 | { "--output", 'o', RTGETOPT_REQ_STRING },
|
---|
3421 | { "--signature-index", 'i', RTGETOPT_REQ_UINT32 },
|
---|
3422 | { "--force", 'f', RTGETOPT_REQ_NOTHING },
|
---|
3423 | { "--as-c-array", 'C', RTGETOPT_REQ_STRING },
|
---|
3424 | };
|
---|
3425 |
|
---|
3426 | const char *pszExe = NULL;
|
---|
3427 | const char *pszOut = NULL;
|
---|
3428 | RTLDRARCH enmLdrArch = RTLDRARCH_WHATEVER;
|
---|
3429 | unsigned cVerbosity = 0;
|
---|
3430 | uint32_t fCursorFlags = RTASN1CURSOR_FLAGS_DER;
|
---|
3431 | uint32_t iSignature = 0;
|
---|
3432 | const char *pszCArrayNm = NULL;
|
---|
3433 | bool fForce = false;
|
---|
3434 |
|
---|
3435 | RTGETOPTSTATE GetState;
|
---|
3436 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
3437 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
3438 | RTGETOPTUNION ValueUnion;
|
---|
3439 | int ch;
|
---|
3440 | while ((ch = RTGetOpt(&GetState, &ValueUnion)))
|
---|
3441 | {
|
---|
3442 | switch (ch)
|
---|
3443 | {
|
---|
3444 | case 'e': pszExe = ValueUnion.psz; break;
|
---|
3445 | case 'o': pszOut = ValueUnion.psz; break;
|
---|
3446 | case 'b': fCursorFlags = 0; break;
|
---|
3447 | case 'c': fCursorFlags = RTASN1CURSOR_FLAGS_CER; break;
|
---|
3448 | case 'd': fCursorFlags = RTASN1CURSOR_FLAGS_DER; break;
|
---|
3449 | case 'f': fForce = true; break;
|
---|
3450 | case 'i': iSignature = ValueUnion.u32; break;
|
---|
3451 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
3452 | case 'h': return HelpExtractExeSignerCert(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
3453 |
|
---|
3454 | case 'C':
|
---|
3455 | pszCArrayNm = *ValueUnion.psz ? ValueUnion.psz : NULL;
|
---|
3456 | if (pszCArrayNm)
|
---|
3457 | iSignature = UINT32_MAX;
|
---|
3458 | break;
|
---|
3459 |
|
---|
3460 | case VINF_GETOPT_NOT_OPTION:
|
---|
3461 | if (!pszExe)
|
---|
3462 | pszExe = ValueUnion.psz;
|
---|
3463 | else if (!pszOut)
|
---|
3464 | pszOut = ValueUnion.psz;
|
---|
3465 | else
|
---|
3466 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz);
|
---|
3467 | break;
|
---|
3468 |
|
---|
3469 | default:
|
---|
3470 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
3471 | }
|
---|
3472 | }
|
---|
3473 | if (!pszExe)
|
---|
3474 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");
|
---|
3475 | if (!pszOut)
|
---|
3476 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output file given.");
|
---|
3477 | if (!fForce && RTPathExists(pszOut))
|
---|
3478 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "The output file '%s' exists.", pszOut);
|
---|
3479 |
|
---|
3480 | /*
|
---|
3481 | * Do it.
|
---|
3482 | */
|
---|
3483 | /* Read & decode the PKCS#7 signature. */
|
---|
3484 | SIGNTOOLPKCS7EXE This;
|
---|
3485 | RTEXITCODE rcExit = SignToolPkcs7Exe_InitFromFile(&This, pszExe, cVerbosity, enmLdrArch);
|
---|
3486 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
3487 | {
|
---|
3488 | if (pszCArrayNm == NULL || iSignature != UINT32_MAX)
|
---|
3489 | {
|
---|
3490 | /* Find the signing certificate (ASSUMING that the certificate used is shipped in the set of certificates). */
|
---|
3491 | PRTCRPKCS7SIGNEDDATA pSignedData;
|
---|
3492 | PCRTCRPKCS7SIGNERINFO pSignerInfo = SignToolPkcs7_FindNestedSignatureByIndex(&This, iSignature, &pSignedData);
|
---|
3493 | rcExit = RTEXITCODE_FAILURE;
|
---|
3494 | if (pSignerInfo)
|
---|
3495 | {
|
---|
3496 | PCRTCRPKCS7ISSUERANDSERIALNUMBER pISN = &pSignedData->SignerInfos.papItems[0]->IssuerAndSerialNumber;
|
---|
3497 | PCRTCRX509CERTIFICATE pCert;
|
---|
3498 | pCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSignedData->Certificates,
|
---|
3499 | &pISN->Name, &pISN->SerialNumber);
|
---|
3500 | if (pCert)
|
---|
3501 | {
|
---|
3502 | /*
|
---|
3503 | * Write it out.
|
---|
3504 | */
|
---|
3505 | if (pszCArrayNm == NULL)
|
---|
3506 | rcExit = WriteCertToFile(pCert, pszOut, fForce);
|
---|
3507 | else
|
---|
3508 | rcExit = WriteCertToFileAsC(pCert, pszOut, fForce, pszCArrayNm);
|
---|
3509 | }
|
---|
3510 | else
|
---|
3511 | RTMsgError("Certificate not found.");
|
---|
3512 | }
|
---|
3513 | else
|
---|
3514 | RTMsgError("Could not locate signature #%u!", iSignature);
|
---|
3515 | }
|
---|
3516 | else
|
---|
3517 | {
|
---|
3518 | uint32_t const cSignatures = SignToolPkcs7_CountSignatures(&This);
|
---|
3519 | if (cSignatures)
|
---|
3520 | {
|
---|
3521 | PRTSTREAM pStrm = NULL;
|
---|
3522 | rc = RTStrmOpen(pszOut, fForce ? "wt+" : "wtx", &pStrm);
|
---|
3523 | if (RT_SUCCESS(rc))
|
---|
3524 | {
|
---|
3525 | for (iSignature = 0; iSignature < cSignatures; iSignature++)
|
---|
3526 | {
|
---|
3527 | PRTCRPKCS7SIGNEDDATA pSignedData;
|
---|
3528 | PCRTCRPKCS7SIGNERINFO pSignerInfo = SignToolPkcs7_FindNestedSignatureByIndex(&This, iSignature, &pSignedData);
|
---|
3529 | if (!pSignerInfo)
|
---|
3530 | {
|
---|
3531 | rcExit = RTMsgErrorExitFailure("Could not locate signature #%u out of %u!", iSignature, cSignatures);
|
---|
3532 | break;
|
---|
3533 | }
|
---|
3534 | PCRTCRPKCS7ISSUERANDSERIALNUMBER pISN = &pSignedData->SignerInfos.papItems[0]->IssuerAndSerialNumber;
|
---|
3535 | PCRTCRX509CERTIFICATE pCert;
|
---|
3536 | pCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(&pSignedData->Certificates,
|
---|
3537 | &pISN->Name, &pISN->SerialNumber);
|
---|
3538 | if (pCert)
|
---|
3539 | PrintCertAsCArray(pCert, iSignature, pszCArrayNm, pStrm);
|
---|
3540 | else
|
---|
3541 | {
|
---|
3542 | rcExit = RTMsgErrorExitFailure("Could not locate certificate for signature #%u (out of %u)!",
|
---|
3543 | iSignature, cSignatures);
|
---|
3544 | break;
|
---|
3545 | }
|
---|
3546 | }
|
---|
3547 |
|
---|
3548 | PrintCertTableAsC(iSignature, pszCArrayNm, pStrm);
|
---|
3549 |
|
---|
3550 | rc = RTStrmClose(pStrm);
|
---|
3551 | if (RT_FAILURE(rc))
|
---|
3552 | rcExit = RTMsgErrorExitFailure("Error writing/closing '%s': %Rrc", pszOut, rc);
|
---|
3553 | }
|
---|
3554 | else
|
---|
3555 | rcExit = RTMsgErrorExitFailure("Failed to open '%s' for writing: %Rrc", pszOut, rc);
|
---|
3556 | }
|
---|
3557 | else
|
---|
3558 | rcExit = RTMsgErrorExitFailure("No signatures found!");
|
---|
3559 | }
|
---|
3560 |
|
---|
3561 | /* Delete the signature data. */
|
---|
3562 | SignToolPkcs7Exe_Delete(&This);
|
---|
3563 | }
|
---|
3564 | return rcExit;
|
---|
3565 | }
|
---|
3566 |
|
---|
3567 |
|
---|
3568 | /*********************************************************************************************************************************
|
---|
3569 | * The 'extract-signer-root' & 'extract-timestamp-root' commands. *
|
---|
3570 | *********************************************************************************************************************************/
|
---|
3571 | class BaseExtractState
|
---|
3572 | {
|
---|
3573 | public:
|
---|
3574 | const char *pszFile;
|
---|
3575 | const char *pszOut;
|
---|
3576 | RTLDRARCH enmLdrArch;
|
---|
3577 | unsigned cVerbosity;
|
---|
3578 | uint32_t iSignature;
|
---|
3579 | bool fForce;
|
---|
3580 | /** Timestamp or main signature. */
|
---|
3581 | bool const fTimestamp;
|
---|
3582 | const char *pszBaseNm;
|
---|
3583 |
|
---|
3584 | BaseExtractState(bool a_fTimestamp)
|
---|
3585 | : pszFile(NULL)
|
---|
3586 | , pszOut(NULL)
|
---|
3587 | , enmLdrArch(RTLDRARCH_WHATEVER)
|
---|
3588 | , cVerbosity(0)
|
---|
3589 | , iSignature(0)
|
---|
3590 | , fForce(false)
|
---|
3591 | , fTimestamp(a_fTimestamp)
|
---|
3592 | , pszBaseNm(NULL)
|
---|
3593 | {
|
---|
3594 | }
|
---|
3595 | };
|
---|
3596 |
|
---|
3597 | class RootExtractState : public BaseExtractState
|
---|
3598 | {
|
---|
3599 | public:
|
---|
3600 | CryptoStore RootStore;
|
---|
3601 | CryptoStore AdditionalStore;
|
---|
3602 |
|
---|
3603 | RootExtractState(bool a_fTimestamp)
|
---|
3604 | : BaseExtractState(a_fTimestamp)
|
---|
3605 | , RootStore()
|
---|
3606 | , AdditionalStore()
|
---|
3607 | { }
|
---|
3608 |
|
---|
3609 | /**
|
---|
3610 | * Creates the two stores, filling the root one with trusted CAs and
|
---|
3611 | * certificates found on the system or in the user's account.
|
---|
3612 | */
|
---|
3613 | bool init(void)
|
---|
3614 | {
|
---|
3615 | int rc = RTCrStoreCreateInMem(&this->RootStore.m_hStore, 0);
|
---|
3616 | if (RT_SUCCESS(rc))
|
---|
3617 | {
|
---|
3618 | rc = RTCrStoreCreateInMem(&this->AdditionalStore.m_hStore, 0);
|
---|
3619 | if (RT_SUCCESS(rc))
|
---|
3620 | return true;
|
---|
3621 | }
|
---|
3622 | RTMsgError("RTCrStoreCreateInMem failed: %Rrc", rc);
|
---|
3623 | return false;
|
---|
3624 | }
|
---|
3625 | };
|
---|
3626 |
|
---|
3627 |
|
---|
3628 | /**
|
---|
3629 | * Locates the target signature and certificate collection.
|
---|
3630 | */
|
---|
3631 | static PRTCRPKCS7SIGNERINFO BaseExtractFindSignerInfo(SIGNTOOLPKCS7 *pThis, BaseExtractState *pState, bool fOptional,
|
---|
3632 | PRTCRPKCS7SIGNEDDATA *ppSignedData, PCRTCRPKCS7SETOFCERTS *ppCerts)
|
---|
3633 | {
|
---|
3634 | *ppSignedData = NULL;
|
---|
3635 | *ppCerts = NULL;
|
---|
3636 |
|
---|
3637 | /*
|
---|
3638 | * Locate the target signature.
|
---|
3639 | */
|
---|
3640 | PRTCRPKCS7SIGNEDDATA pSignedData = NULL;
|
---|
3641 | PRTCRPKCS7SIGNERINFO pSignerInfo = SignToolPkcs7_FindNestedSignatureByIndex(pThis, pState->iSignature, &pSignedData);
|
---|
3642 | if (pSignerInfo)
|
---|
3643 | {
|
---|
3644 | /*
|
---|
3645 | * If the target is the timestamp we have to locate the relevant
|
---|
3646 | * timestamp signature and adjust the return values.
|
---|
3647 | */
|
---|
3648 | if (pState->fTimestamp)
|
---|
3649 | {
|
---|
3650 | for (uint32_t iItem = 0; iItem < pSignerInfo->UnauthenticatedAttributes.cItems; iItem++)
|
---|
3651 | {
|
---|
3652 | PCRTCRPKCS7ATTRIBUTE pAttr = pSignerInfo->UnauthenticatedAttributes.papItems[iItem];
|
---|
3653 | if (pAttr->enmType == RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES)
|
---|
3654 | {
|
---|
3655 | /* ASSUME that all counter signatures are timestamping. */
|
---|
3656 | if (pAttr->uValues.pCounterSignatures->cItems > 0)
|
---|
3657 | {
|
---|
3658 | *ppSignedData = pSignedData;
|
---|
3659 | *ppCerts = &pSignedData->Certificates;
|
---|
3660 | return pAttr->uValues.pCounterSignatures->papItems[0];
|
---|
3661 | }
|
---|
3662 | RTMsgWarning("Timestamp signature attribute is empty!");
|
---|
3663 | }
|
---|
3664 | else if (pAttr->enmType == RTCRPKCS7ATTRIBUTETYPE_MS_TIMESTAMP)
|
---|
3665 | {
|
---|
3666 | /* ASSUME that all valid timestamp signatures for now, pick the first. */
|
---|
3667 | if (pAttr->uValues.pContentInfos->cItems > 0)
|
---|
3668 | {
|
---|
3669 | PCRTCRPKCS7CONTENTINFO pContentInfo = pAttr->uValues.pContentInfos->papItems[0];
|
---|
3670 | if (RTAsn1ObjId_CompareWithString(&pContentInfo->ContentType, RTCR_PKCS7_SIGNED_DATA_OID) == 0)
|
---|
3671 | {
|
---|
3672 | pSignedData = pContentInfo->u.pSignedData;
|
---|
3673 | if (RTAsn1ObjId_CompareWithString(&pSignedData->ContentInfo.ContentType, RTCRTSPTSTINFO_OID) == 0)
|
---|
3674 | {
|
---|
3675 | if (pSignedData->SignerInfos.cItems > 0)
|
---|
3676 | {
|
---|
3677 | *ppSignedData = pSignedData;
|
---|
3678 | *ppCerts = &pSignedData->Certificates;
|
---|
3679 | return pSignedData->SignerInfos.papItems[0];
|
---|
3680 | }
|
---|
3681 | RTMsgWarning("Timestamp signature has no signers!");
|
---|
3682 | }
|
---|
3683 | else
|
---|
3684 | RTMsgWarning("Timestamp signature contains wrong content (%s)!",
|
---|
3685 | pSignedData->ContentInfo.ContentType.szObjId);
|
---|
3686 | }
|
---|
3687 | else
|
---|
3688 | RTMsgWarning("Timestamp signature is not SignedData but %s!", pContentInfo->ContentType.szObjId);
|
---|
3689 | }
|
---|
3690 | else
|
---|
3691 | RTMsgWarning("Timestamp signature attribute is empty!");
|
---|
3692 | }
|
---|
3693 | }
|
---|
3694 | if (!fOptional)
|
---|
3695 | RTMsgError("Cound not find a timestamp signature associated with signature #%u!", pState->iSignature);
|
---|
3696 | pSignerInfo = NULL;
|
---|
3697 | }
|
---|
3698 | else
|
---|
3699 | {
|
---|
3700 | *ppSignedData = pSignedData;
|
---|
3701 | *ppCerts = &pSignedData->Certificates;
|
---|
3702 | }
|
---|
3703 | }
|
---|
3704 | else if (!fOptional)
|
---|
3705 | RTMsgError("Could not locate signature #%u!", pState->iSignature);
|
---|
3706 | return pSignerInfo;
|
---|
3707 | }
|
---|
3708 |
|
---|
3709 |
|
---|
3710 | /** @callback_method_impl{FNRTDUMPPRINTFV} */
|
---|
3711 | static DECLCALLBACK(void) DumpToStdOutPrintfV(void *pvUser, const char *pszFormat, va_list va)
|
---|
3712 | {
|
---|
3713 | RT_NOREF(pvUser);
|
---|
3714 | RTPrintfV(pszFormat, va);
|
---|
3715 | }
|
---|
3716 |
|
---|
3717 |
|
---|
3718 | static RTEXITCODE RootExtractWorker3(SIGNTOOLPKCS7 *pThis, RootExtractState *pState, PRTSTREAM pStrm, uint32_t *pidxCert,
|
---|
3719 | PRTERRINFOSTATIC pStaticErrInfo)
|
---|
3720 | {
|
---|
3721 | /*
|
---|
3722 | * Locate the target signature.
|
---|
3723 | */
|
---|
3724 | bool const fOptional = pidxCert != NULL && pStrm != NULL && pState->fTimestamp /*fOptional*/;
|
---|
3725 | PRTCRPKCS7SIGNEDDATA pSignedData;
|
---|
3726 | PCRTCRPKCS7SETOFCERTS pCerts;
|
---|
3727 | PCRTCRPKCS7SIGNERINFO pSignerInfo = BaseExtractFindSignerInfo(pThis, pState, fOptional, &pSignedData, &pCerts);
|
---|
3728 | if (!pSignerInfo)
|
---|
3729 | {
|
---|
3730 | if (!fOptional)
|
---|
3731 | return RTMsgErrorExitFailure("Could not locate signature #%u!", pState->iSignature);
|
---|
3732 | return RTEXITCODE_SUCCESS;
|
---|
3733 | }
|
---|
3734 |
|
---|
3735 |
|
---|
3736 | /* The next bit is modelled on first half of rtCrPkcs7VerifySignerInfo. */
|
---|
3737 |
|
---|
3738 | /*
|
---|
3739 | * Locate the signing certificate.
|
---|
3740 | */
|
---|
3741 | PCRTCRCERTCTX pSignerCertCtx = RTCrStoreCertByIssuerAndSerialNo(pState->RootStore.m_hStore,
|
---|
3742 | &pSignerInfo->IssuerAndSerialNumber.Name,
|
---|
3743 | &pSignerInfo->IssuerAndSerialNumber.SerialNumber);
|
---|
3744 | if (!pSignerCertCtx)
|
---|
3745 | pSignerCertCtx = RTCrStoreCertByIssuerAndSerialNo(pState->AdditionalStore.m_hStore,
|
---|
3746 | &pSignerInfo->IssuerAndSerialNumber.Name,
|
---|
3747 | &pSignerInfo->IssuerAndSerialNumber.SerialNumber);
|
---|
3748 |
|
---|
3749 | PCRTCRX509CERTIFICATE pSignerCert;
|
---|
3750 | if (pSignerCertCtx)
|
---|
3751 | pSignerCert = pSignerCertCtx->pCert;
|
---|
3752 | else
|
---|
3753 | {
|
---|
3754 | pSignerCert = RTCrPkcs7SetOfCerts_FindX509ByIssuerAndSerialNumber(pCerts,
|
---|
3755 | &pSignerInfo->IssuerAndSerialNumber.Name,
|
---|
3756 | &pSignerInfo->IssuerAndSerialNumber.SerialNumber);
|
---|
3757 | if (!pSignerCert)
|
---|
3758 | return RTMsgErrorExitFailure("Certificate not found: serial=%.*Rhxs",
|
---|
3759 | pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.cb,
|
---|
3760 | pSignerInfo->IssuerAndSerialNumber.SerialNumber.Asn1Core.uData.pv);
|
---|
3761 | }
|
---|
3762 |
|
---|
3763 | /*
|
---|
3764 | * Now we build paths so we can get to the root certificate.
|
---|
3765 | */
|
---|
3766 | RTCRX509CERTPATHS hCertPaths;
|
---|
3767 | int rc = RTCrX509CertPathsCreate(&hCertPaths, pSignerCert);
|
---|
3768 | if (RT_FAILURE(rc))
|
---|
3769 | return RTMsgErrorExitFailure("RTCrX509CertPathsCreate failed: %Rrc", rc);
|
---|
3770 |
|
---|
3771 | /* Configure: */
|
---|
3772 | RTEXITCODE rcExit = RTEXITCODE_FAILURE;
|
---|
3773 | rc = RTCrX509CertPathsSetTrustedStore(hCertPaths, pState->RootStore.m_hStore);
|
---|
3774 | if (RT_SUCCESS(rc))
|
---|
3775 | {
|
---|
3776 | rc = RTCrX509CertPathsSetUntrustedStore(hCertPaths, pState->AdditionalStore.m_hStore);
|
---|
3777 | if (RT_SUCCESS(rc))
|
---|
3778 | {
|
---|
3779 | rc = RTCrX509CertPathsSetUntrustedSet(hCertPaths, pCerts);
|
---|
3780 | if (RT_SUCCESS(rc))
|
---|
3781 | {
|
---|
3782 | /* We don't technically need this, I think. */
|
---|
3783 | rc = RTCrX509CertPathsSetTrustAnchorChecks(hCertPaths, true /*fEnable*/);
|
---|
3784 | if (RT_SUCCESS(rc))
|
---|
3785 | {
|
---|
3786 | /* Seems we might need this for the sha-1 certs and such. */
|
---|
3787 | RTCrX509CertPathsSetValidTimeSpec(hCertPaths, NULL);
|
---|
3788 |
|
---|
3789 | /* Build the paths: */
|
---|
3790 | rc = RTCrX509CertPathsBuild(hCertPaths, RTErrInfoInitStatic(pStaticErrInfo));
|
---|
3791 | if (RT_SUCCESS(rc))
|
---|
3792 | {
|
---|
3793 | uint32_t const cPaths = RTCrX509CertPathsGetPathCount(hCertPaths);
|
---|
3794 |
|
---|
3795 | /* Validate the paths: */
|
---|
3796 | uint32_t cValidPaths = 0;
|
---|
3797 | rc = RTCrX509CertPathsValidateAll(hCertPaths, &cValidPaths, RTErrInfoInitStatic(pStaticErrInfo));
|
---|
3798 | if (RT_SUCCESS(rc))
|
---|
3799 | {
|
---|
3800 | if (pState->cVerbosity > 0)
|
---|
3801 | RTMsgInfo("%u of %u paths are valid", cValidPaths, cPaths);
|
---|
3802 | if (pState->cVerbosity > 1)
|
---|
3803 | RTCrX509CertPathsDumpAll(hCertPaths, pState->cVerbosity, DumpToStdOutPrintfV, NULL);
|
---|
3804 |
|
---|
3805 | /*
|
---|
3806 | * Now, pick the first valid path with a real certificate at the end.
|
---|
3807 | */
|
---|
3808 | for (uint32_t iPath = 0; iPath < cPaths; iPath++)
|
---|
3809 | {
|
---|
3810 | PCRTCRX509CERTIFICATE pRootCert = NULL;
|
---|
3811 | PCRTCRX509NAME pSubject = NULL;
|
---|
3812 | bool fTrusted = false;
|
---|
3813 | int rcVerify = -1;
|
---|
3814 | rc = RTCrX509CertPathsQueryPathInfo(hCertPaths, iPath, &fTrusted, NULL /*pcNodes*/,
|
---|
3815 | &pSubject, NULL, &pRootCert, NULL /*ppCertCtx*/, &rcVerify);
|
---|
3816 | if (RT_SUCCESS(rc))
|
---|
3817 | {
|
---|
3818 | if (fTrusted && RT_SUCCESS(rcVerify) && pRootCert)
|
---|
3819 | {
|
---|
3820 | /*
|
---|
3821 | * Now copy out the certificate.
|
---|
3822 | */
|
---|
3823 | if (!pState->pszBaseNm)
|
---|
3824 | rcExit = WriteCertToFile(pRootCert, pState->pszOut, pState->fForce);
|
---|
3825 | else if (!pStrm)
|
---|
3826 | rcExit = WriteCertToFileAsC(pRootCert, pState->pszOut, pState->fForce,
|
---|
3827 | pState->pszBaseNm);
|
---|
3828 | else
|
---|
3829 | {
|
---|
3830 | PrintCertAsCArray(pRootCert, *pidxCert, pState->pszBaseNm, pStrm);
|
---|
3831 | *pidxCert += 1;
|
---|
3832 | rcExit = RTEXITCODE_SUCCESS;
|
---|
3833 | }
|
---|
3834 | break;
|
---|
3835 | }
|
---|
3836 | }
|
---|
3837 | else
|
---|
3838 | {
|
---|
3839 | RTMsgError("RTCrX509CertPathsQueryPathInfo failed: %Rrc", rc);
|
---|
3840 | break;
|
---|
3841 | }
|
---|
3842 | }
|
---|
3843 | }
|
---|
3844 | else
|
---|
3845 | {
|
---|
3846 | RTMsgError("RTCrX509CertPathsValidateAll failed: %Rrc%#RTeim", rc, &pStaticErrInfo->Core);
|
---|
3847 | RTCrX509CertPathsDumpAll(hCertPaths, pState->cVerbosity, DumpToStdOutPrintfV, NULL);
|
---|
3848 | }
|
---|
3849 | }
|
---|
3850 | else
|
---|
3851 | RTMsgError("RTCrX509CertPathsBuild failed: %Rrc%#RTeim", rc, &pStaticErrInfo->Core);
|
---|
3852 | }
|
---|
3853 | else
|
---|
3854 | RTMsgError("RTCrX509CertPathsSetTrustAnchorChecks failed: %Rrc", rc);
|
---|
3855 | }
|
---|
3856 | else
|
---|
3857 | RTMsgError("RTCrX509CertPathsSetUntrustedSet failed: %Rrc", rc);
|
---|
3858 | }
|
---|
3859 | else
|
---|
3860 | RTMsgError("RTCrX509CertPathsSetUntrustedStore failed: %Rrc", rc);
|
---|
3861 | }
|
---|
3862 | else
|
---|
3863 | RTMsgError("RTCrX509CertPathsSetTrustedStore failed: %Rrc", rc);
|
---|
3864 |
|
---|
3865 | uint32_t cRefs = RTCrX509CertPathsRelease(hCertPaths);
|
---|
3866 | Assert(cRefs == 0); RT_NOREF(cRefs);
|
---|
3867 |
|
---|
3868 | return rcExit;
|
---|
3869 | }
|
---|
3870 |
|
---|
3871 |
|
---|
3872 | static RTEXITCODE RootExtractWorker2(SIGNTOOLPKCS7 *pThis, RootExtractState *pState, PRTERRINFOSTATIC pStaticErrInfo)
|
---|
3873 | {
|
---|
3874 | if (!pState->pszBaseNm || pState->iSignature != UINT32_MAX)
|
---|
3875 | return RootExtractWorker3(pThis, pState, NULL, NULL, pStaticErrInfo);
|
---|
3876 |
|
---|
3877 | /*
|
---|
3878 | * Dump all these certificates.
|
---|
3879 | */
|
---|
3880 | uint32_t const cSignatures = SignToolPkcs7_CountSignatures(pThis);
|
---|
3881 | if (!cSignatures)
|
---|
3882 | return RTMsgErrorExitFailure("No signatures found!");
|
---|
3883 |
|
---|
3884 | PRTSTREAM pStrm = NULL;
|
---|
3885 | int rc = RTStrmOpen(pState->pszOut, pState->fForce ? "wt+" : "wtx", &pStrm);
|
---|
3886 | if (RT_FAILURE(rc))
|
---|
3887 | return RTMsgErrorExitFailure("Failed to open '%s' for writing: %Rrc", pState->pszOut, rc);
|
---|
3888 |
|
---|
3889 | uint32_t idxCert = 0; /* tracking separately, as we ignore missing timestamp chains. */
|
---|
3890 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
3891 | for (uint32_t iSignature = 0; iSignature < cSignatures && rcExit == RTEXITCODE_SUCCESS; iSignature++)
|
---|
3892 | {
|
---|
3893 | pState->iSignature = iSignature;
|
---|
3894 | rcExit = RootExtractWorker3(pThis, pState, pStrm, &idxCert, pStaticErrInfo);
|
---|
3895 | }
|
---|
3896 |
|
---|
3897 | PrintCertTableAsC(idxCert, pState->pszBaseNm, pStrm);
|
---|
3898 |
|
---|
3899 | rc = RTStrmClose(pStrm);
|
---|
3900 | if (RT_FAILURE(rc))
|
---|
3901 | rcExit = RTMsgErrorExitFailure("Error writing/closing '%s': %Rrc", pState->pszOut, rc);
|
---|
3902 | return rcExit;
|
---|
3903 | }
|
---|
3904 |
|
---|
3905 |
|
---|
3906 | static RTEXITCODE RootExtractWorker(RootExtractState *pState, PRTERRINFOSTATIC pStaticErrInfo)
|
---|
3907 | {
|
---|
3908 | /*
|
---|
3909 | * Check that all we need is there and whether the output file exists.
|
---|
3910 | */
|
---|
3911 | if (!pState->pszFile)
|
---|
3912 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");
|
---|
3913 | if (!pState->pszOut)
|
---|
3914 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output file given.");
|
---|
3915 | if (!pState->fForce && RTPathExists(pState->pszOut))
|
---|
3916 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "The output file '%s' exists.", pState->pszOut);
|
---|
3917 |
|
---|
3918 | /*
|
---|
3919 | * Detect the type of file we're dealing with, do type specific setup and
|
---|
3920 | * call common worker to do the rest.
|
---|
3921 | */
|
---|
3922 | RTEXITCODE rcExit;
|
---|
3923 | RTSIGNTOOLFILETYPE enmFileType = DetectFileType(RTSIGNTOOLFILETYPE_DETECT, pState->pszFile);
|
---|
3924 | if (enmFileType == RTSIGNTOOLFILETYPE_EXE)
|
---|
3925 | {
|
---|
3926 | SIGNTOOLPKCS7EXE Exe;
|
---|
3927 | rcExit = SignToolPkcs7Exe_InitFromFile(&Exe, pState->pszFile, pState->cVerbosity, pState->enmLdrArch);
|
---|
3928 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
3929 | {
|
---|
3930 | rcExit = RootExtractWorker2(&Exe, pState, pStaticErrInfo);
|
---|
3931 | SignToolPkcs7Exe_Delete(&Exe);
|
---|
3932 | }
|
---|
3933 | }
|
---|
3934 | else if (enmFileType == RTSIGNTOOLFILETYPE_CAT)
|
---|
3935 | {
|
---|
3936 | SIGNTOOLPKCS7 Cat;
|
---|
3937 | rcExit = SignToolPkcs7_InitFromFile(&Cat, pState->pszFile, pState->cVerbosity);
|
---|
3938 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
3939 | {
|
---|
3940 | rcExit = RootExtractWorker2(&Cat, pState, pStaticErrInfo);
|
---|
3941 | SignToolPkcs7_Delete(&Cat);
|
---|
3942 | }
|
---|
3943 | }
|
---|
3944 | else
|
---|
3945 | rcExit = RTEXITCODE_FAILURE;
|
---|
3946 | return rcExit;
|
---|
3947 | }
|
---|
3948 |
|
---|
3949 |
|
---|
3950 | static RTEXITCODE HelpExtractRootCommon(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel, bool fTimestamp)
|
---|
3951 | {
|
---|
3952 | RT_NOREF_PV(enmLevel);
|
---|
3953 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
3954 | "extract-%s-root [-v|--verbose] [-q|--quiet] [--as-c-array <name>] [--signature-index|-i <num>] "
|
---|
3955 | "[--root <root-cert.der>] [--self-signed-roots-from-system] [--additional <supp-cert.der>] "
|
---|
3956 | "[--intermediate-certs-from-system] [--input] <signed-file> "
|
---|
3957 | "[-f|--force] [--output|-o] <outfile.cer/h>\n",
|
---|
3958 | fTimestamp ? "timestamp" : "signer");
|
---|
3959 | if (enmLevel == RTSIGNTOOLHELP_FULL)
|
---|
3960 | {
|
---|
3961 | RTStrmWrappedPrintf(pStrm, 0,
|
---|
3962 | "\n"
|
---|
3963 | "Extracts the root certificate of the %sgiven "
|
---|
3964 | "signature. If there are more than one valid certificate path, the first one with "
|
---|
3965 | "a full certificate will be picked.\n",
|
---|
3966 | fTimestamp ? "first timestamp associated with the " : "");
|
---|
3967 | RTStrmWrappedPrintf(pStrm, 0,
|
---|
3968 | "\n"
|
---|
3969 | "Options:\n"
|
---|
3970 | " -v, --verbose, -q, --quite\n"
|
---|
3971 | " Controls the noise level. The '-v' options are accumlative while '-q' is absolute.\n"
|
---|
3972 | " Default: -q\n"
|
---|
3973 | " -C <name>, --as-c-array <name>\n"
|
---|
3974 | " Output a C header file containing the roots of all signatures (or a selected one if"
|
---|
3975 | "--signature-index is used again after this option.\n"
|
---|
3976 | " Default: Output one binary certificate.\n"
|
---|
3977 | " -i <num>, --signature-index <num>\n"
|
---|
3978 | " Zero-based index of the signature to extract the root for.\n"
|
---|
3979 | " Default: -i 0\n"
|
---|
3980 | " -r <root-cert.file>, --root <root-cert.file>\n"
|
---|
3981 | " Use the certificate(s) in the specified file as a trusted root(s). "
|
---|
3982 | "The file format can be PEM or DER.\n"
|
---|
3983 | " -R, --self-signed-roots-from-system\n"
|
---|
3984 | " Use all self-signed trusted root certificates found on the system and associated with the "
|
---|
3985 | "current user as trusted roots. This is limited to self-signed certificates, so that we get "
|
---|
3986 | "a full chain even if a non-end-entity certificate is present in any of those system stores for "
|
---|
3987 | "some reason.\n"
|
---|
3988 | " -a <supp-cert.file>, --additional <supp-cert.file>\n"
|
---|
3989 | " Use the certificate(s) in the specified file as a untrusted intermediate certificates. "
|
---|
3990 | "The file format can be PEM or DER.\n"
|
---|
3991 | " -A, --intermediate-certs-from-system\n"
|
---|
3992 | " Use all certificates found on the system and associated with the current user as intermediate "
|
---|
3993 | "certification authorities.\n"
|
---|
3994 | " --input <signed-file>\n"
|
---|
3995 | " Signed executable or security cabinet file to examine. The '--input' option bit is optional "
|
---|
3996 | "and there to allow more flexible parameter ordering.\n"
|
---|
3997 | " -f, --force\n"
|
---|
3998 | " Overwrite existing output file. The default is not to overwriting any existing file.\n"
|
---|
3999 | " -o <outfile.cer> --output <outfile.cer>\n"
|
---|
4000 | " The name of the output file. Again the '-o|--output' bit is optional and only for flexibility.\n"
|
---|
4001 | );
|
---|
4002 | }
|
---|
4003 | return RTEXITCODE_SUCCESS;
|
---|
4004 | }
|
---|
4005 |
|
---|
4006 |
|
---|
4007 | static RTEXITCODE HandleExtractRootCommon(int cArgs, char **papszArgs, bool fTimestamp)
|
---|
4008 | {
|
---|
4009 | /*
|
---|
4010 | * Parse arguments.
|
---|
4011 | */
|
---|
4012 | static const RTGETOPTDEF s_aOptions[] =
|
---|
4013 | {
|
---|
4014 | { "--root", 'r', RTGETOPT_REQ_STRING },
|
---|
4015 | { "--self-signed-roots-from-system", 'R', RTGETOPT_REQ_NOTHING },
|
---|
4016 | { "--additional", 'a', RTGETOPT_REQ_STRING },
|
---|
4017 | { "--intermediate-certs-from-system",'A', RTGETOPT_REQ_NOTHING },
|
---|
4018 | { "--add", 'a', RTGETOPT_REQ_STRING },
|
---|
4019 | { "--input", 'I', RTGETOPT_REQ_STRING },
|
---|
4020 | { "--output", 'o', RTGETOPT_REQ_STRING },
|
---|
4021 | { "--signature-index", 'i', RTGETOPT_REQ_UINT32 },
|
---|
4022 | { "--force", 'f', RTGETOPT_REQ_NOTHING },
|
---|
4023 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
4024 | { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
|
---|
4025 | { "--as-c-array", 'C', RTGETOPT_REQ_STRING },
|
---|
4026 | };
|
---|
4027 | RTERRINFOSTATIC StaticErrInfo;
|
---|
4028 | RootExtractState State(fTimestamp);
|
---|
4029 | if (!State.init())
|
---|
4030 | return RTEXITCODE_FAILURE;
|
---|
4031 | RTGETOPTSTATE GetState;
|
---|
4032 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
4033 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
4034 | RTGETOPTUNION ValueUnion;
|
---|
4035 | int ch;
|
---|
4036 | while ((ch = RTGetOpt(&GetState, &ValueUnion)))
|
---|
4037 | {
|
---|
4038 | switch (ch)
|
---|
4039 | {
|
---|
4040 | case 'a':
|
---|
4041 | if (!State.AdditionalStore.addFromFile(ValueUnion.psz, &StaticErrInfo))
|
---|
4042 | return RTEXITCODE_FAILURE;
|
---|
4043 | break;
|
---|
4044 |
|
---|
4045 | case 'A':
|
---|
4046 | if (!State.AdditionalStore.addIntermediateCertsFromSystem(&StaticErrInfo))
|
---|
4047 | return RTEXITCODE_FAILURE;
|
---|
4048 | break;
|
---|
4049 |
|
---|
4050 | case 'r':
|
---|
4051 | if (!State.RootStore.addFromFile(ValueUnion.psz, &StaticErrInfo))
|
---|
4052 | return RTEXITCODE_FAILURE;
|
---|
4053 | break;
|
---|
4054 |
|
---|
4055 | case 'R':
|
---|
4056 | if (!State.RootStore.addSelfSignedRootsFromSystem(&StaticErrInfo))
|
---|
4057 | return RTEXITCODE_FAILURE;
|
---|
4058 | break;
|
---|
4059 |
|
---|
4060 | case 'I': State.pszFile = ValueUnion.psz; break;
|
---|
4061 | case 'o': State.pszOut = ValueUnion.psz; break;
|
---|
4062 | case 'f': State.fForce = true; break;
|
---|
4063 | case 'i': State.iSignature = ValueUnion.u32; break;
|
---|
4064 | case 'v': State.cVerbosity++; break;
|
---|
4065 | case 'q': State.cVerbosity = 0; break;
|
---|
4066 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
4067 | case 'h': return HelpExtractRootCommon(g_pStdOut, RTSIGNTOOLHELP_FULL, fTimestamp);
|
---|
4068 |
|
---|
4069 | case 'C':
|
---|
4070 | State.pszBaseNm = *ValueUnion.psz ? ValueUnion.psz : NULL;
|
---|
4071 | if (State.pszBaseNm)
|
---|
4072 | State.iSignature = UINT32_MAX;
|
---|
4073 | break;
|
---|
4074 |
|
---|
4075 | case VINF_GETOPT_NOT_OPTION:
|
---|
4076 | if (!State.pszFile)
|
---|
4077 | State.pszFile = ValueUnion.psz;
|
---|
4078 | else if (!State.pszOut)
|
---|
4079 | State.pszOut = ValueUnion.psz;
|
---|
4080 | else
|
---|
4081 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz);
|
---|
4082 | break;
|
---|
4083 |
|
---|
4084 | default:
|
---|
4085 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
4086 | }
|
---|
4087 | }
|
---|
4088 | return RootExtractWorker(&State, &StaticErrInfo);
|
---|
4089 | }
|
---|
4090 |
|
---|
4091 |
|
---|
4092 | static RTEXITCODE HelpExtractSignerRoot(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
4093 | {
|
---|
4094 | return HelpExtractRootCommon(pStrm, enmLevel, false /*fTimestamp*/);
|
---|
4095 | }
|
---|
4096 |
|
---|
4097 |
|
---|
4098 | static RTEXITCODE HandleExtractSignerRoot(int cArgs, char **papszArgs)
|
---|
4099 | {
|
---|
4100 | return HandleExtractRootCommon(cArgs, papszArgs, false /*fTimestamp*/ );
|
---|
4101 | }
|
---|
4102 |
|
---|
4103 |
|
---|
4104 | static RTEXITCODE HelpExtractTimestampRoot(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
4105 | {
|
---|
4106 | return HelpExtractRootCommon(pStrm, enmLevel, true /*fTimestamp*/);
|
---|
4107 | }
|
---|
4108 |
|
---|
4109 |
|
---|
4110 | static RTEXITCODE HandleExtractTimestampRoot(int cArgs, char **papszArgs)
|
---|
4111 | {
|
---|
4112 | return HandleExtractRootCommon(cArgs, papszArgs, true /*fTimestamp*/ );
|
---|
4113 | }
|
---|
4114 |
|
---|
4115 |
|
---|
4116 | /*********************************************************************************************************************************
|
---|
4117 | * The 'extract-exe-signature' command. *
|
---|
4118 | *********************************************************************************************************************************/
|
---|
4119 |
|
---|
4120 | static RTEXITCODE HelpExtractExeSignature(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
4121 | {
|
---|
4122 | RT_NOREF_PV(enmLevel);
|
---|
4123 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
4124 | "extract-exe-signerature [--input|--exe|-e] <exe> [--output|-o] <outfile.pkcs7>\n");
|
---|
4125 | return RTEXITCODE_SUCCESS;
|
---|
4126 | }
|
---|
4127 |
|
---|
4128 | static RTEXITCODE HandleExtractExeSignature(int cArgs, char **papszArgs)
|
---|
4129 | {
|
---|
4130 | /*
|
---|
4131 | * Parse arguments.
|
---|
4132 | */
|
---|
4133 | static const RTGETOPTDEF s_aOptions[] =
|
---|
4134 | {
|
---|
4135 | { "--exe", 'e', RTGETOPT_REQ_STRING },
|
---|
4136 | { "--input", 'e', RTGETOPT_REQ_STRING },
|
---|
4137 | { "--output", 'o', RTGETOPT_REQ_STRING },
|
---|
4138 | { "--force", 'f', RTGETOPT_REQ_NOTHING },
|
---|
4139 | };
|
---|
4140 |
|
---|
4141 | const char *pszExe = NULL;
|
---|
4142 | const char *pszOut = NULL;
|
---|
4143 | RTLDRARCH enmLdrArch = RTLDRARCH_WHATEVER;
|
---|
4144 | unsigned cVerbosity = 0;
|
---|
4145 | bool fForce = false;
|
---|
4146 |
|
---|
4147 | RTGETOPTSTATE GetState;
|
---|
4148 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
4149 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
4150 | RTGETOPTUNION ValueUnion;
|
---|
4151 | int ch;
|
---|
4152 | while ((ch = RTGetOpt(&GetState, &ValueUnion)))
|
---|
4153 | {
|
---|
4154 | switch (ch)
|
---|
4155 | {
|
---|
4156 | case 'e': pszExe = ValueUnion.psz; break;
|
---|
4157 | case 'o': pszOut = ValueUnion.psz; break;
|
---|
4158 | case 'f': fForce = true; break;
|
---|
4159 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
4160 | case 'h': return HelpExtractExeSignerCert(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
4161 |
|
---|
4162 | case VINF_GETOPT_NOT_OPTION:
|
---|
4163 | if (!pszExe)
|
---|
4164 | pszExe = ValueUnion.psz;
|
---|
4165 | else if (!pszOut)
|
---|
4166 | pszOut = ValueUnion.psz;
|
---|
4167 | else
|
---|
4168 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz);
|
---|
4169 | break;
|
---|
4170 |
|
---|
4171 | default:
|
---|
4172 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
4173 | }
|
---|
4174 | }
|
---|
4175 | if (!pszExe)
|
---|
4176 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");
|
---|
4177 | if (!pszOut)
|
---|
4178 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output file given.");
|
---|
4179 | if (!fForce && RTPathExists(pszOut))
|
---|
4180 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "The output file '%s' exists.", pszOut);
|
---|
4181 |
|
---|
4182 | /*
|
---|
4183 | * Do it.
|
---|
4184 | */
|
---|
4185 | /* Read & decode the PKCS#7 signature. */
|
---|
4186 | SIGNTOOLPKCS7EXE This;
|
---|
4187 | RTEXITCODE rcExit = SignToolPkcs7Exe_InitFromFile(&This, pszExe, cVerbosity, enmLdrArch);
|
---|
4188 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
4189 | {
|
---|
4190 | /*
|
---|
4191 | * Write out the PKCS#7 signature.
|
---|
4192 | */
|
---|
4193 | RTFILE hFile;
|
---|
4194 | rc = RTFileOpen(&hFile, pszOut,
|
---|
4195 | RTFILE_O_WRITE | RTFILE_O_DENY_WRITE | (fForce ? RTFILE_O_CREATE_REPLACE : RTFILE_O_CREATE));
|
---|
4196 | if (RT_SUCCESS(rc))
|
---|
4197 | {
|
---|
4198 | rc = RTFileWrite(hFile, This.pbBuf, This.cbBuf, NULL);
|
---|
4199 | if (RT_SUCCESS(rc))
|
---|
4200 | {
|
---|
4201 | rc = RTFileClose(hFile);
|
---|
4202 | if (RT_SUCCESS(rc))
|
---|
4203 | {
|
---|
4204 | hFile = NIL_RTFILE;
|
---|
4205 | RTMsgInfo("Successfully wrote %u bytes to '%s'", This.cbBuf, pszOut);
|
---|
4206 | rcExit = RTEXITCODE_SUCCESS;
|
---|
4207 | }
|
---|
4208 | else
|
---|
4209 | RTMsgError("RTFileClose failed: %Rrc", rc);
|
---|
4210 | }
|
---|
4211 | else
|
---|
4212 | RTMsgError("RTFileWrite failed: %Rrc", rc);
|
---|
4213 | RTFileClose(hFile);
|
---|
4214 | }
|
---|
4215 | else
|
---|
4216 | RTMsgError("Error opening '%s' for writing: %Rrc", pszOut, rc);
|
---|
4217 |
|
---|
4218 | /* Delete the signature data. */
|
---|
4219 | SignToolPkcs7Exe_Delete(&This);
|
---|
4220 | }
|
---|
4221 | return rcExit;
|
---|
4222 | }
|
---|
4223 |
|
---|
4224 |
|
---|
4225 | /*********************************************************************************************************************************
|
---|
4226 | * The 'add-nested-exe-signature' command. *
|
---|
4227 | *********************************************************************************************************************************/
|
---|
4228 |
|
---|
4229 | static RTEXITCODE HelpAddNestedExeSignature(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
4230 | {
|
---|
4231 | RT_NOREF_PV(enmLevel);
|
---|
4232 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
4233 | "add-nested-exe-signature [-v|--verbose] [-d|--debug] [-p|--prepend] <destination-exe> <source-exe>\n");
|
---|
4234 | if (enmLevel == RTSIGNTOOLHELP_FULL)
|
---|
4235 | RTStrmWrappedPrintf(pStrm, 0,
|
---|
4236 | "\n"
|
---|
4237 | "The --debug option allows the source-exe to be omitted in order to test the "
|
---|
4238 | "encoding and PE file modification.\n"
|
---|
4239 | "\n"
|
---|
4240 | "The --prepend option puts the nested signature first rather than appending it "
|
---|
4241 | "to the end of of the nested signature set. Windows reads nested signatures in "
|
---|
4242 | "reverse order, so --prepend will logically putting it last.\n");
|
---|
4243 | return RTEXITCODE_SUCCESS;
|
---|
4244 | }
|
---|
4245 |
|
---|
4246 |
|
---|
4247 | static RTEXITCODE HandleAddNestedExeSignature(int cArgs, char **papszArgs)
|
---|
4248 | {
|
---|
4249 | /*
|
---|
4250 | * Parse arguments.
|
---|
4251 | */
|
---|
4252 | static const RTGETOPTDEF s_aOptions[] =
|
---|
4253 | {
|
---|
4254 | { "--prepend", 'p', RTGETOPT_REQ_NOTHING },
|
---|
4255 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
4256 | { "--debug", 'd', RTGETOPT_REQ_NOTHING },
|
---|
4257 | };
|
---|
4258 |
|
---|
4259 | const char *pszDst = NULL;
|
---|
4260 | const char *pszSrc = NULL;
|
---|
4261 | unsigned cVerbosity = 0;
|
---|
4262 | bool fDebug = false;
|
---|
4263 | bool fPrepend = false;
|
---|
4264 |
|
---|
4265 | RTGETOPTSTATE GetState;
|
---|
4266 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
4267 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
4268 | RTGETOPTUNION ValueUnion;
|
---|
4269 | int ch;
|
---|
4270 | while ((ch = RTGetOpt(&GetState, &ValueUnion)))
|
---|
4271 | {
|
---|
4272 | switch (ch)
|
---|
4273 | {
|
---|
4274 | case 'v': cVerbosity++; break;
|
---|
4275 | case 'd': fDebug = pszSrc == NULL; break;
|
---|
4276 | case 'p': fPrepend = true; break;
|
---|
4277 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
4278 | case 'h': return HelpAddNestedExeSignature(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
4279 |
|
---|
4280 | case VINF_GETOPT_NOT_OPTION:
|
---|
4281 | if (!pszDst)
|
---|
4282 | pszDst = ValueUnion.psz;
|
---|
4283 | else if (!pszSrc)
|
---|
4284 | {
|
---|
4285 | pszSrc = ValueUnion.psz;
|
---|
4286 | fDebug = false;
|
---|
4287 | }
|
---|
4288 | else
|
---|
4289 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz);
|
---|
4290 | break;
|
---|
4291 |
|
---|
4292 | default:
|
---|
4293 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
4294 | }
|
---|
4295 | }
|
---|
4296 | if (!pszDst)
|
---|
4297 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No destination executable given.");
|
---|
4298 | if (!pszSrc && !fDebug)
|
---|
4299 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No source executable file given.");
|
---|
4300 |
|
---|
4301 | /*
|
---|
4302 | * Do it.
|
---|
4303 | */
|
---|
4304 | /* Read & decode the source PKCS#7 signature. */
|
---|
4305 | SIGNTOOLPKCS7EXE Src;
|
---|
4306 | RTEXITCODE rcExit = pszSrc ? SignToolPkcs7Exe_InitFromFile(&Src, pszSrc, cVerbosity) : RTEXITCODE_SUCCESS;
|
---|
4307 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
4308 | {
|
---|
4309 | /* Ditto for the destination PKCS#7 signature. */
|
---|
4310 | SIGNTOOLPKCS7EXE Dst;
|
---|
4311 | rcExit = SignToolPkcs7Exe_InitFromFile(&Dst, pszDst, cVerbosity);
|
---|
4312 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
4313 | {
|
---|
4314 | /* Do the signature manipulation. */
|
---|
4315 | if (pszSrc)
|
---|
4316 | rcExit = SignToolPkcs7_AddNestedSignature(&Dst, &Src, cVerbosity, fPrepend);
|
---|
4317 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
4318 | rcExit = SignToolPkcs7_Encode(&Dst, cVerbosity);
|
---|
4319 |
|
---|
4320 | /* Update the destination executable file. */
|
---|
4321 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
4322 | rcExit = SignToolPkcs7Exe_WriteSignatureToFile(&Dst, cVerbosity);
|
---|
4323 |
|
---|
4324 | SignToolPkcs7Exe_Delete(&Dst);
|
---|
4325 | }
|
---|
4326 | if (pszSrc)
|
---|
4327 | SignToolPkcs7Exe_Delete(&Src);
|
---|
4328 | }
|
---|
4329 |
|
---|
4330 | return rcExit;
|
---|
4331 | }
|
---|
4332 |
|
---|
4333 |
|
---|
4334 | /*********************************************************************************************************************************
|
---|
4335 | * The 'add-nested-cat-signature' command. *
|
---|
4336 | *********************************************************************************************************************************/
|
---|
4337 |
|
---|
4338 | static RTEXITCODE HelpAddNestedCatSignature(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
4339 | {
|
---|
4340 | RT_NOREF_PV(enmLevel);
|
---|
4341 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
4342 | "add-nested-cat-signature [-v|--verbose] [-d|--debug] [-p|--prepend] <destination-cat> <source-cat>\n");
|
---|
4343 | if (enmLevel == RTSIGNTOOLHELP_FULL)
|
---|
4344 | RTStrmWrappedPrintf(pStrm, 0,
|
---|
4345 | "\n"
|
---|
4346 | "The --debug option allows the source-cat to be omitted in order to test the "
|
---|
4347 | "ASN.1 re-encoding of the destination catalog file.\n"
|
---|
4348 | "\n"
|
---|
4349 | "The --prepend option puts the nested signature first rather than appending it "
|
---|
4350 | "to the end of of the nested signature set. Windows reads nested signatures in "
|
---|
4351 | "reverse order, so --prepend will logically putting it last.\n");
|
---|
4352 | return RTEXITCODE_SUCCESS;
|
---|
4353 | }
|
---|
4354 |
|
---|
4355 |
|
---|
4356 | static RTEXITCODE HandleAddNestedCatSignature(int cArgs, char **papszArgs)
|
---|
4357 | {
|
---|
4358 | /*
|
---|
4359 | * Parse arguments.
|
---|
4360 | */
|
---|
4361 | static const RTGETOPTDEF s_aOptions[] =
|
---|
4362 | {
|
---|
4363 | { "--prepend", 'p', RTGETOPT_REQ_NOTHING },
|
---|
4364 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
4365 | { "--debug", 'd', RTGETOPT_REQ_NOTHING },
|
---|
4366 | };
|
---|
4367 |
|
---|
4368 | const char *pszDst = NULL;
|
---|
4369 | const char *pszSrc = NULL;
|
---|
4370 | unsigned cVerbosity = 0;
|
---|
4371 | bool fDebug = false;
|
---|
4372 | bool fPrepend = false;
|
---|
4373 |
|
---|
4374 | RTGETOPTSTATE GetState;
|
---|
4375 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
4376 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
4377 | RTGETOPTUNION ValueUnion;
|
---|
4378 | int ch;
|
---|
4379 | while ((ch = RTGetOpt(&GetState, &ValueUnion)))
|
---|
4380 | {
|
---|
4381 | switch (ch)
|
---|
4382 | {
|
---|
4383 | case 'v': cVerbosity++; break;
|
---|
4384 | case 'd': fDebug = pszSrc == NULL; break;
|
---|
4385 | case 'p': fPrepend = true; break;
|
---|
4386 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
4387 | case 'h': return HelpAddNestedCatSignature(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
4388 |
|
---|
4389 | case VINF_GETOPT_NOT_OPTION:
|
---|
4390 | if (!pszDst)
|
---|
4391 | pszDst = ValueUnion.psz;
|
---|
4392 | else if (!pszSrc)
|
---|
4393 | {
|
---|
4394 | pszSrc = ValueUnion.psz;
|
---|
4395 | fDebug = false;
|
---|
4396 | }
|
---|
4397 | else
|
---|
4398 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many file arguments: %s", ValueUnion.psz);
|
---|
4399 | break;
|
---|
4400 |
|
---|
4401 | default:
|
---|
4402 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
4403 | }
|
---|
4404 | }
|
---|
4405 | if (!pszDst)
|
---|
4406 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No destination catalog file given.");
|
---|
4407 | if (!pszSrc && !fDebug)
|
---|
4408 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No source catalog file given.");
|
---|
4409 |
|
---|
4410 | /*
|
---|
4411 | * Do it.
|
---|
4412 | */
|
---|
4413 | /* Read & decode the source PKCS#7 signature. */
|
---|
4414 | SIGNTOOLPKCS7 Src;
|
---|
4415 | RTEXITCODE rcExit = pszSrc ? SignToolPkcs7_InitFromFile(&Src, pszSrc, cVerbosity) : RTEXITCODE_SUCCESS;
|
---|
4416 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
4417 | {
|
---|
4418 | /* Ditto for the destination PKCS#7 signature. */
|
---|
4419 | SIGNTOOLPKCS7EXE Dst;
|
---|
4420 | rcExit = SignToolPkcs7_InitFromFile(&Dst, pszDst, cVerbosity);
|
---|
4421 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
4422 | {
|
---|
4423 | /* Do the signature manipulation. */
|
---|
4424 | if (pszSrc)
|
---|
4425 | rcExit = SignToolPkcs7_AddNestedSignature(&Dst, &Src, cVerbosity, fPrepend);
|
---|
4426 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
4427 | rcExit = SignToolPkcs7_Encode(&Dst, cVerbosity);
|
---|
4428 |
|
---|
4429 | /* Update the destination executable file. */
|
---|
4430 | if (rcExit == RTEXITCODE_SUCCESS)
|
---|
4431 | rcExit = SignToolPkcs7_WriteSignatureToFile(&Dst, pszDst, cVerbosity);
|
---|
4432 |
|
---|
4433 | SignToolPkcs7_Delete(&Dst);
|
---|
4434 | }
|
---|
4435 | if (pszSrc)
|
---|
4436 | SignToolPkcs7_Delete(&Src);
|
---|
4437 | }
|
---|
4438 |
|
---|
4439 | return rcExit;
|
---|
4440 | }
|
---|
4441 |
|
---|
4442 |
|
---|
4443 | /*********************************************************************************************************************************
|
---|
4444 | * The 'add-timestamp-exe-signature' command. *
|
---|
4445 | *********************************************************************************************************************************/
|
---|
4446 | #ifndef IPRT_SIGNTOOL_NO_SIGNING
|
---|
4447 |
|
---|
4448 | static RTEXITCODE HelpAddTimestampExeSignature(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
4449 | {
|
---|
4450 | RT_NOREF_PV(enmLevel);
|
---|
4451 |
|
---|
4452 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
4453 | "add-timestamp-exe-signature [-v|--verbose] [--signature-index|-i <num>] "
|
---|
4454 | OPT_CERT_KEY_SYNOPSIS("--timestamp-", "")
|
---|
4455 | "[--timestamp-type old|new] "
|
---|
4456 | "[--timestamp-override <partial-isots>] "
|
---|
4457 | "[--replace-existing|-r] "
|
---|
4458 | "<exe>\n");
|
---|
4459 | if (enmLevel == RTSIGNTOOLHELP_FULL)
|
---|
4460 | RTStrmWrappedPrintf(pStrm, 0,
|
---|
4461 | "This is mainly to test timestamp code.\n"
|
---|
4462 | "\n"
|
---|
4463 | "The --timestamp-override option can take a partial or full ISO timestamp. It is merged "
|
---|
4464 | "with the current time if partial.\n"
|
---|
4465 | "\n");
|
---|
4466 | return RTEXITCODE_SUCCESS;
|
---|
4467 | }
|
---|
4468 |
|
---|
4469 | static RTEXITCODE HandleAddTimestampExeSignature(int cArgs, char **papszArgs)
|
---|
4470 | {
|
---|
4471 | /*
|
---|
4472 | * Parse arguments.
|
---|
4473 | */
|
---|
4474 | static const RTGETOPTDEF s_aOptions[] =
|
---|
4475 | {
|
---|
4476 | { "--signature-index", 'i', RTGETOPT_REQ_UINT32 },
|
---|
4477 | OPT_CERT_KEY_GETOPTDEF_ENTRIES("--timestamp-", "", 1000),
|
---|
4478 | { "--timestamp-type", OPT_TIMESTAMP_TYPE, RTGETOPT_REQ_STRING },
|
---|
4479 | { "--timestamp-override", OPT_TIMESTAMP_OVERRIDE, RTGETOPT_REQ_STRING },
|
---|
4480 | { "--replace-existing", 'r', RTGETOPT_REQ_NOTHING },
|
---|
4481 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
4482 | };
|
---|
4483 |
|
---|
4484 | unsigned cVerbosity = 0;
|
---|
4485 | unsigned iSignature = 0;
|
---|
4486 | bool fReplaceExisting = false;
|
---|
4487 | SignToolTimestampOpts TimestampOpts("timestamp");
|
---|
4488 | RTTIMESPEC SigningTime;
|
---|
4489 | RTTimeNow(&SigningTime);
|
---|
4490 |
|
---|
4491 | RTGETOPTSTATE GetState;
|
---|
4492 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
4493 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
4494 |
|
---|
4495 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
4496 | RTGETOPTUNION ValueUnion;
|
---|
4497 | int ch;
|
---|
4498 | while ((ch = RTGetOpt(&GetState, &ValueUnion)))
|
---|
4499 | {
|
---|
4500 | RTEXITCODE rcExit2 = RTEXITCODE_SUCCESS;
|
---|
4501 | switch (ch)
|
---|
4502 | {
|
---|
4503 | OPT_CERT_KEY_SWITCH_CASES(TimestampOpts, 1000, ch, ValueUnion, rcExit2);
|
---|
4504 | case 'i': iSignature = ValueUnion.u32; break;
|
---|
4505 | case OPT_TIMESTAMP_TYPE: rcExit2 = HandleOptTimestampType(&TimestampOpts, ValueUnion.psz); break;
|
---|
4506 | case OPT_TIMESTAMP_OVERRIDE: rcExit2 = HandleOptTimestampOverride(&SigningTime, ValueUnion.psz); break;
|
---|
4507 | case 'r': fReplaceExisting = true; break;
|
---|
4508 | case 'v': cVerbosity++; break;
|
---|
4509 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
4510 | case 'h': return HelpAddTimestampExeSignature(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
4511 |
|
---|
4512 | case VINF_GETOPT_NOT_OPTION:
|
---|
4513 | /* Do final certificate and key option processing (first file only). */
|
---|
4514 | rcExit2 = TimestampOpts.finalizeOptions(cVerbosity);
|
---|
4515 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4516 | {
|
---|
4517 | /* Do the work: */
|
---|
4518 | SIGNTOOLPKCS7EXE Exe;
|
---|
4519 | rcExit2 = SignToolPkcs7Exe_InitFromFile(&Exe, ValueUnion.psz, cVerbosity);
|
---|
4520 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4521 | {
|
---|
4522 | rcExit2 = SignToolPkcs7_AddTimestampSignature(&Exe, cVerbosity, iSignature, fReplaceExisting,
|
---|
4523 | SigningTime, &TimestampOpts);
|
---|
4524 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4525 | rcExit2 = SignToolPkcs7_Encode(&Exe, cVerbosity);
|
---|
4526 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4527 | rcExit2 = SignToolPkcs7Exe_WriteSignatureToFile(&Exe, cVerbosity);
|
---|
4528 | SignToolPkcs7Exe_Delete(&Exe);
|
---|
4529 | }
|
---|
4530 | if (rcExit2 != RTEXITCODE_SUCCESS && rcExit == RTEXITCODE_SUCCESS)
|
---|
4531 | rcExit = rcExit2;
|
---|
4532 | rcExit2 = RTEXITCODE_SUCCESS;
|
---|
4533 | }
|
---|
4534 | break;
|
---|
4535 |
|
---|
4536 | default:
|
---|
4537 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
4538 | }
|
---|
4539 |
|
---|
4540 | if (rcExit2 != RTEXITCODE_SUCCESS)
|
---|
4541 | {
|
---|
4542 | rcExit = rcExit2;
|
---|
4543 | break;
|
---|
4544 | }
|
---|
4545 | }
|
---|
4546 | return rcExit;
|
---|
4547 | }
|
---|
4548 |
|
---|
4549 | #endif /*!IPRT_SIGNTOOL_NO_SIGNING */
|
---|
4550 |
|
---|
4551 |
|
---|
4552 | /*********************************************************************************************************************************
|
---|
4553 | * The 'sign-exe' command. *
|
---|
4554 | *********************************************************************************************************************************/
|
---|
4555 | #ifndef IPRT_SIGNTOOL_NO_SIGNING
|
---|
4556 |
|
---|
4557 | static RTEXITCODE HelpSign(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
4558 | {
|
---|
4559 | RT_NOREF_PV(enmLevel);
|
---|
4560 |
|
---|
4561 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
4562 | "sign [-v|--verbose] "
|
---|
4563 | "[--file-type exe|cat] "
|
---|
4564 | "[--type|/fd sha1|sha256] "
|
---|
4565 | "[--hash-pages|/ph] "
|
---|
4566 | "[--no-hash-pages|/nph] "
|
---|
4567 | "[--append/as] "
|
---|
4568 | "[--no-signing-time] "
|
---|
4569 | "[--add-cert <file>] "
|
---|
4570 | "[--timestamp-type old|new] "
|
---|
4571 | "[--timestamp-override <partial-isots>] "
|
---|
4572 | "[--verbose|/debug|-v] "
|
---|
4573 | OPT_CERT_KEY_SYNOPSIS("--", "")
|
---|
4574 | OPT_CERT_KEY_SYNOPSIS("--timestamp-", "")
|
---|
4575 | //OPT_CERT_KEY_SYNOPSIS("--timestamp-", "-2") - doesn't work, windows only uses one. Check again with new-style signatures
|
---|
4576 | "<exe>\n");
|
---|
4577 | if (enmLevel == RTSIGNTOOLHELP_FULL)
|
---|
4578 | RTStrmWrappedPrintf(pStrm, 0,
|
---|
4579 | "\n"
|
---|
4580 | "Create a new code signature for an executable or catalog.\n"
|
---|
4581 | "\n"
|
---|
4582 | "Options:\n"
|
---|
4583 | " --append, /as\n"
|
---|
4584 | " Append the signature if one already exists. The default is to replace any existing signature.\n"
|
---|
4585 | " --type sha1|sha256, /fd sha1|sha256\n"
|
---|
4586 | " Signature type, SHA-1 or SHA-256.\n"
|
---|
4587 | " --hash-pages, /ph, --no-page-hashes, /nph\n"
|
---|
4588 | " Enables or disables page hashing. Ignored for catalog files. Default: --no-page-hashes\n"
|
---|
4589 | " --add-cert <file>, /ac <file>\n"
|
---|
4590 | " Adds (first) certificate from the file to the signature. Both PEM and DER (binary) encodings "
|
---|
4591 | "are accepted. Repeat to add more certiifcates.\n"
|
---|
4592 | " --timestamp-override <partial-iso-timestamp>\n"
|
---|
4593 | " This specifies the signing time as a ISO timestamp. Partial timestamps are merged with the "
|
---|
4594 | "current time. This is applied to any timestamp signature as well as the signingTime attribute of "
|
---|
4595 | "main signature. Higher resolution than seconds is not supported. Default: Current time.\n"
|
---|
4596 | " --no-signing-time\n"
|
---|
4597 | " Don't set the signing time on the main signature, only on the timestamp one. Unfortunately, "
|
---|
4598 | "this doesn't work without modifying OpenSSL a little.\n"
|
---|
4599 | " --timestamp-type old|new\n"
|
---|
4600 | " Selects the timstamp type. 'old' is the old style /t <url> stuff from signtool.exe. "
|
---|
4601 | "'new' means a RTC-3161 timstamp - currently not implemented. Default: old\n"
|
---|
4602 | //" --timestamp-type-2 old|new\n"
|
---|
4603 | //" Same as --timestamp-type but for the 2nd timstamp signature.\n"
|
---|
4604 | "\n"
|
---|
4605 | //"Certificate and Key Options (--timestamp-cert-name[-2] etc for timestamps):\n"
|
---|
4606 | "Certificate and Key Options (--timestamp-cert-name etc for timestamps):\n"
|
---|
4607 | " --cert-subject <partial name>, /n <partial name>\n"
|
---|
4608 | " Locate the main signature signing certificate and key, unless anything else is given, "
|
---|
4609 | "by the given name substring. Overrides any previous --cert-sha1 and --cert-file options.\n"
|
---|
4610 | " --cert-sha1 <hex bytes>, /sha1 <hex bytes>\n"
|
---|
4611 | " Locate the main signature signing certificate and key, unless anything else is given, "
|
---|
4612 | "by the given thumbprint. The hex bytes can be space separated, colon separated, just "
|
---|
4613 | "bunched together, or a mix of these. This overrids any previous --cert-name and --cert-file "
|
---|
4614 | "options.\n"
|
---|
4615 | " --cert-store <name>, /s <store>\n"
|
---|
4616 | " Certificate store to search when using --cert-name or --cert-sha1. Default: MY\n"
|
---|
4617 | " --cert-machine-store, /sm\n"
|
---|
4618 | " Use the machine store rather the ones of the current user.\n"
|
---|
4619 | " --cert-file <file>, /f <file>\n"
|
---|
4620 | " Load the certificate and key, unless anything else is given, from given file. Both PEM and "
|
---|
4621 | "DER (binary) encodings are supported. Keys file can be RSA or PKCS#12 formatted.\n"
|
---|
4622 | " --key-file <file>\n"
|
---|
4623 | " Load the private key from the given file. Support RSA and PKCS#12 formatted files.\n"
|
---|
4624 | " --key-password <password>, /p <password>\n"
|
---|
4625 | " Password to use to decrypt a PKCS#12 password file.\n"
|
---|
4626 | " --key-password-file <file>|stdin\n"
|
---|
4627 | " Load password to decrypt the password file from the given file or from stdin.\n"
|
---|
4628 | " --key-name <name>, /kc <name>\n"
|
---|
4629 | " The private key container name. Not implemented.\n"
|
---|
4630 | " --key-provider <name>, /csp <name>\n"
|
---|
4631 | " The name of the crypto provider where the private key conatiner specified via --key-name "
|
---|
4632 | "can be found.\n"
|
---|
4633 | );
|
---|
4634 |
|
---|
4635 | return RTEXITCODE_SUCCESS;
|
---|
4636 | }
|
---|
4637 |
|
---|
4638 |
|
---|
4639 | static RTEXITCODE HandleSign(int cArgs, char **papszArgs)
|
---|
4640 | {
|
---|
4641 | /*
|
---|
4642 | * Parse arguments.
|
---|
4643 | */
|
---|
4644 | static const RTGETOPTDEF s_aOptions[] =
|
---|
4645 | {
|
---|
4646 | { "--append", 'A', RTGETOPT_REQ_NOTHING },
|
---|
4647 | { "/as", 'A', RTGETOPT_REQ_NOTHING },
|
---|
4648 | { "/a", OPT_IGNORED, RTGETOPT_REQ_NOTHING }, /* select best cert automatically */
|
---|
4649 | { "--type", 't', RTGETOPT_REQ_STRING },
|
---|
4650 | { "/fd", 't', RTGETOPT_REQ_STRING },
|
---|
4651 | { "--hash-pages", OPT_HASH_PAGES, RTGETOPT_REQ_NOTHING },
|
---|
4652 | { "/ph", OPT_HASH_PAGES, RTGETOPT_REQ_NOTHING },
|
---|
4653 | { "--no-hash-pages", OPT_NO_HASH_PAGES, RTGETOPT_REQ_NOTHING },
|
---|
4654 | { "/nph", OPT_NO_HASH_PAGES, RTGETOPT_REQ_NOTHING },
|
---|
4655 | { "--add-cert", OPT_ADD_CERT, RTGETOPT_REQ_STRING },
|
---|
4656 | { "/ac", OPT_ADD_CERT, RTGETOPT_REQ_STRING },
|
---|
4657 | { "--description", 'd', RTGETOPT_REQ_STRING },
|
---|
4658 | { "--desc", 'd', RTGETOPT_REQ_STRING },
|
---|
4659 | { "/d", 'd', RTGETOPT_REQ_STRING },
|
---|
4660 | { "--description-url", 'D', RTGETOPT_REQ_STRING },
|
---|
4661 | { "--desc-url", 'D', RTGETOPT_REQ_STRING },
|
---|
4662 | { "/du", 'D', RTGETOPT_REQ_STRING },
|
---|
4663 | { "--no-signing-time", OPT_NO_SIGNING_TIME, RTGETOPT_REQ_NOTHING },
|
---|
4664 | OPT_CERT_KEY_GETOPTDEF_ENTRIES("--", "", 1000),
|
---|
4665 | OPT_CERT_KEY_GETOPTDEF_COMPAT_ENTRIES( 1000),
|
---|
4666 | OPT_CERT_KEY_GETOPTDEF_ENTRIES("--timestamp-", "", 1020),
|
---|
4667 | //OPT_CERT_KEY_GETOPTDEF_ENTRIES("--timestamp-", "-1", 1020),
|
---|
4668 | //OPT_CERT_KEY_GETOPTDEF_ENTRIES("--timestamp-", "-2", 1040), - disabled as windows cannot make use of it. Try again when
|
---|
4669 | // new-style timestamp signatures has been implemented. Otherwise, just add two primary signatures with the two
|
---|
4670 | // different timestamps certificates / hashes / whatever.
|
---|
4671 | { "--timestamp-type", OPT_TIMESTAMP_TYPE, RTGETOPT_REQ_STRING },
|
---|
4672 | { "--timestamp-type-1", OPT_TIMESTAMP_TYPE, RTGETOPT_REQ_STRING },
|
---|
4673 | { "--timestamp-type-2", OPT_TIMESTAMP_TYPE_2, RTGETOPT_REQ_STRING },
|
---|
4674 | { "--timestamp-override", OPT_TIMESTAMP_OVERRIDE, RTGETOPT_REQ_STRING },
|
---|
4675 | { "--file-type", OPT_FILE_TYPE, RTGETOPT_REQ_STRING },
|
---|
4676 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
4677 | { "/v", 'v', RTGETOPT_REQ_NOTHING },
|
---|
4678 | { "/debug", 'v', RTGETOPT_REQ_NOTHING },
|
---|
4679 | };
|
---|
4680 |
|
---|
4681 | unsigned cVerbosity = 0;
|
---|
4682 | RTDIGESTTYPE enmSigType = RTDIGESTTYPE_SHA1;
|
---|
4683 | bool fReplaceExisting = true;
|
---|
4684 | bool fHashPages = false;
|
---|
4685 | bool fNoSigningTime = false;
|
---|
4686 | RTSIGNTOOLFILETYPE enmForceFileType = RTSIGNTOOLFILETYPE_DETECT;
|
---|
4687 | SignToolKeyPair SigningCertKey("signing", true);
|
---|
4688 | CryptoStore AddCerts;
|
---|
4689 | const char *pszDescription = NULL; /** @todo implement putting descriptions into the OpusInfo stuff. */
|
---|
4690 | const char *pszDescriptionUrl = NULL;
|
---|
4691 | SignToolTimestampOpts aTimestampOpts[2] = { SignToolTimestampOpts("timestamp"), SignToolTimestampOpts("timestamp#2") };
|
---|
4692 | RTTIMESPEC SigningTime;
|
---|
4693 | RTTimeNow(&SigningTime);
|
---|
4694 |
|
---|
4695 | RTGETOPTSTATE GetState;
|
---|
4696 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
4697 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
4698 |
|
---|
4699 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
4700 | RTGETOPTUNION ValueUnion;
|
---|
4701 | int ch;
|
---|
4702 | while ((ch = RTGetOpt(&GetState, &ValueUnion)))
|
---|
4703 | {
|
---|
4704 | RTEXITCODE rcExit2 = RTEXITCODE_SUCCESS;
|
---|
4705 | switch (ch)
|
---|
4706 | {
|
---|
4707 | OPT_CERT_KEY_SWITCH_CASES(SigningCertKey, 1000, ch, ValueUnion, rcExit2);
|
---|
4708 | OPT_CERT_KEY_SWITCH_CASES(aTimestampOpts[0], 1020, ch, ValueUnion, rcExit2);
|
---|
4709 | OPT_CERT_KEY_SWITCH_CASES(aTimestampOpts[1], 1040, ch, ValueUnion, rcExit2);
|
---|
4710 | case 't': rcExit2 = HandleOptSignatureType(&enmSigType, ValueUnion.psz); break;
|
---|
4711 | case 'A': fReplaceExisting = false; break;
|
---|
4712 | case 'd': pszDescription = ValueUnion.psz; break;
|
---|
4713 | case 'D': pszDescriptionUrl = ValueUnion.psz; break;
|
---|
4714 | case OPT_HASH_PAGES: fHashPages = true; break;
|
---|
4715 | case OPT_NO_HASH_PAGES: fHashPages = false; break;
|
---|
4716 | case OPT_NO_SIGNING_TIME: fNoSigningTime = true; break;
|
---|
4717 | case OPT_ADD_CERT: rcExit2 = HandleOptAddCert(&AddCerts.m_hStore, ValueUnion.psz); break;
|
---|
4718 | case OPT_TIMESTAMP_TYPE: rcExit2 = HandleOptTimestampType(&aTimestampOpts[0], ValueUnion.psz); break;
|
---|
4719 | case OPT_TIMESTAMP_TYPE_2: rcExit2 = HandleOptTimestampType(&aTimestampOpts[1], ValueUnion.psz); break;
|
---|
4720 | case OPT_TIMESTAMP_OVERRIDE: rcExit2 = HandleOptTimestampOverride(&SigningTime, ValueUnion.psz); break;
|
---|
4721 | case OPT_FILE_TYPE: rcExit2 = HandleOptFileType(&enmForceFileType, ValueUnion.psz); break;
|
---|
4722 | case OPT_IGNORED: break;
|
---|
4723 | case 'v': cVerbosity++; break;
|
---|
4724 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
4725 | case 'h': return HelpSign(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
4726 |
|
---|
4727 | case VINF_GETOPT_NOT_OPTION:
|
---|
4728 | /*
|
---|
4729 | * Do final certificate and key option processing (first file only).
|
---|
4730 | */
|
---|
4731 | rcExit2 = SigningCertKey.finalizeOptions(cVerbosity);
|
---|
4732 | for (unsigned i = 0; rcExit2 == RTEXITCODE_SUCCESS && i < RT_ELEMENTS(aTimestampOpts); i++)
|
---|
4733 | rcExit2 = aTimestampOpts[i].finalizeOptions(cVerbosity);
|
---|
4734 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4735 | {
|
---|
4736 | /*
|
---|
4737 | * Detect file type.
|
---|
4738 | */
|
---|
4739 | RTSIGNTOOLFILETYPE enmFileType = DetectFileType(enmForceFileType, ValueUnion.psz);
|
---|
4740 | if (enmFileType == RTSIGNTOOLFILETYPE_EXE)
|
---|
4741 | {
|
---|
4742 | /*
|
---|
4743 | * Sign executable image.
|
---|
4744 | */
|
---|
4745 | SIGNTOOLPKCS7EXE Exe;
|
---|
4746 | rcExit2 = SignToolPkcs7Exe_InitFromFile(&Exe, ValueUnion.psz, cVerbosity,
|
---|
4747 | RTLDRARCH_WHATEVER, true /*fAllowUnsigned*/);
|
---|
4748 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4749 | {
|
---|
4750 | rcExit2 = SignToolPkcs7_AddOrReplaceSignature(&Exe, cVerbosity, enmSigType, fReplaceExisting,
|
---|
4751 | fHashPages, fNoSigningTime, &SigningCertKey,
|
---|
4752 | AddCerts.m_hStore, SigningTime,
|
---|
4753 | RT_ELEMENTS(aTimestampOpts), aTimestampOpts);
|
---|
4754 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4755 | rcExit2 = SignToolPkcs7_Encode(&Exe, cVerbosity);
|
---|
4756 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4757 | rcExit2 = SignToolPkcs7Exe_WriteSignatureToFile(&Exe, cVerbosity);
|
---|
4758 | SignToolPkcs7Exe_Delete(&Exe);
|
---|
4759 | }
|
---|
4760 | }
|
---|
4761 | else if (enmFileType == RTSIGNTOOLFILETYPE_CAT)
|
---|
4762 | {
|
---|
4763 | /*
|
---|
4764 | * Sign catalog file.
|
---|
4765 | */
|
---|
4766 | SIGNTOOLPKCS7 Cat;
|
---|
4767 | rcExit2 = SignToolPkcs7_InitFromFile(&Cat, ValueUnion.psz, cVerbosity);
|
---|
4768 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4769 | {
|
---|
4770 | rcExit2 = SignToolPkcs7_AddOrReplaceCatSignature(&Cat, cVerbosity, enmSigType, fReplaceExisting,
|
---|
4771 | fNoSigningTime, &SigningCertKey,
|
---|
4772 | AddCerts.m_hStore, SigningTime,
|
---|
4773 | RT_ELEMENTS(aTimestampOpts), aTimestampOpts);
|
---|
4774 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4775 | rcExit2 = SignToolPkcs7_Encode(&Cat, cVerbosity);
|
---|
4776 | if (rcExit2 == RTEXITCODE_SUCCESS)
|
---|
4777 | rcExit2 = SignToolPkcs7_WriteSignatureToFile(&Cat, ValueUnion.psz, cVerbosity);
|
---|
4778 | SignToolPkcs7_Delete(&Cat);
|
---|
4779 | }
|
---|
4780 | }
|
---|
4781 | else
|
---|
4782 | rcExit2 = RTEXITCODE_FAILURE;
|
---|
4783 | if (rcExit2 != RTEXITCODE_SUCCESS && rcExit == RTEXITCODE_SUCCESS)
|
---|
4784 | rcExit = rcExit2;
|
---|
4785 | rcExit2 = RTEXITCODE_SUCCESS;
|
---|
4786 | }
|
---|
4787 | break;
|
---|
4788 |
|
---|
4789 | default:
|
---|
4790 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
4791 | }
|
---|
4792 | if (rcExit2 != RTEXITCODE_SUCCESS)
|
---|
4793 | {
|
---|
4794 | rcExit = rcExit2;
|
---|
4795 | break;
|
---|
4796 | }
|
---|
4797 | }
|
---|
4798 |
|
---|
4799 | return rcExit;
|
---|
4800 | }
|
---|
4801 |
|
---|
4802 | #endif /*!IPRT_SIGNTOOL_NO_SIGNING */
|
---|
4803 |
|
---|
4804 |
|
---|
4805 | /*********************************************************************************************************************************
|
---|
4806 | * The 'verify-exe' command. *
|
---|
4807 | *********************************************************************************************************************************/
|
---|
4808 | #ifndef IPRT_IN_BUILD_TOOL
|
---|
4809 |
|
---|
4810 | static RTEXITCODE HelpVerifyExe(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
4811 | {
|
---|
4812 | RT_NOREF_PV(enmLevel);
|
---|
4813 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
4814 | "verify-exe [--verbose|--quiet] [--kernel] [--root <root-cert.der>] [--self-signed-roots-from-system] "
|
---|
4815 | "[--additional <supp-cert.der>] [--type <win|osx>] <exe1> [exe2 [..]]\n");
|
---|
4816 | return RTEXITCODE_SUCCESS;
|
---|
4817 | }
|
---|
4818 |
|
---|
4819 | typedef struct VERIFYEXESTATE
|
---|
4820 | {
|
---|
4821 | CryptoStore RootStore;
|
---|
4822 | CryptoStore KernelRootStore;
|
---|
4823 | CryptoStore AdditionalStore;
|
---|
4824 | bool fKernel;
|
---|
4825 | int cVerbose;
|
---|
4826 | enum { kSignType_Windows, kSignType_OSX } enmSignType;
|
---|
4827 | RTLDRARCH enmLdrArch;
|
---|
4828 | uint32_t cBad;
|
---|
4829 | uint32_t cOkay;
|
---|
4830 | const char *pszFilename;
|
---|
4831 | RTTIMESPEC ValidationTime;
|
---|
4832 |
|
---|
4833 | VERIFYEXESTATE()
|
---|
4834 | : fKernel(false)
|
---|
4835 | , cVerbose(0)
|
---|
4836 | , enmSignType(kSignType_Windows)
|
---|
4837 | , enmLdrArch(RTLDRARCH_WHATEVER)
|
---|
4838 | , cBad(0)
|
---|
4839 | , cOkay(0)
|
---|
4840 | , pszFilename(NULL)
|
---|
4841 | {
|
---|
4842 | RTTimeSpecSetSeconds(&ValidationTime, 0);
|
---|
4843 | }
|
---|
4844 | } VERIFYEXESTATE;
|
---|
4845 |
|
---|
4846 | # ifdef VBOX
|
---|
4847 | /** Certificate store load set.
|
---|
4848 | * Declared outside HandleVerifyExe because of braindead gcc visibility crap. */
|
---|
4849 | struct STSTORESET
|
---|
4850 | {
|
---|
4851 | RTCRSTORE hStore;
|
---|
4852 | PCSUPTAENTRY paTAs;
|
---|
4853 | unsigned cTAs;
|
---|
4854 | };
|
---|
4855 | # endif
|
---|
4856 |
|
---|
4857 | /**
|
---|
4858 | * @callback_method_impl{FNRTCRPKCS7VERIFYCERTCALLBACK,
|
---|
4859 | * Standard code signing. Use this for Microsoft SPC.}
|
---|
4860 | */
|
---|
4861 | static DECLCALLBACK(int) VerifyExecCertVerifyCallback(PCRTCRX509CERTIFICATE pCert, RTCRX509CERTPATHS hCertPaths, uint32_t fFlags,
|
---|
4862 | void *pvUser, PRTERRINFO pErrInfo)
|
---|
4863 | {
|
---|
4864 | VERIFYEXESTATE *pState = (VERIFYEXESTATE *)pvUser;
|
---|
4865 | uint32_t cPaths = RTCrX509CertPathsGetPathCount(hCertPaths);
|
---|
4866 |
|
---|
4867 | /*
|
---|
4868 | * Dump all the paths.
|
---|
4869 | */
|
---|
4870 | if (pState->cVerbose > 0)
|
---|
4871 | {
|
---|
4872 | RTPrintf(fFlags & RTCRPKCS7VCC_F_TIMESTAMP ? "Timestamp Path%s:\n" : "Signature Path%s:\n",
|
---|
4873 | cPaths == 1 ? "" : "s");
|
---|
4874 | for (uint32_t iPath = 0; iPath < cPaths; iPath++)
|
---|
4875 | {
|
---|
4876 | //if (iPath != 0)
|
---|
4877 | // RTPrintf("---\n");
|
---|
4878 | RTCrX509CertPathsDumpOne(hCertPaths, iPath, pState->cVerbose, RTStrmDumpPrintfV, g_pStdOut);
|
---|
4879 | *pErrInfo->pszMsg = '\0';
|
---|
4880 | }
|
---|
4881 | //RTPrintf(fFlags & RTCRPKCS7VCC_F_TIMESTAMP ? "--- end timestamp ---\n" : "--- end signature ---\n");
|
---|
4882 | }
|
---|
4883 |
|
---|
4884 | /*
|
---|
4885 | * Test signing certificates normally doesn't have all the necessary
|
---|
4886 | * features required below. So, treat them as special cases.
|
---|
4887 | */
|
---|
4888 | if ( hCertPaths == NIL_RTCRX509CERTPATHS
|
---|
4889 | && RTCrX509Name_Compare(&pCert->TbsCertificate.Issuer, &pCert->TbsCertificate.Subject) == 0)
|
---|
4890 | {
|
---|
4891 | RTMsgInfo("Test signed.\n");
|
---|
4892 | return VINF_SUCCESS;
|
---|
4893 | }
|
---|
4894 |
|
---|
4895 | if (hCertPaths == NIL_RTCRX509CERTPATHS)
|
---|
4896 | RTMsgInfo("Signed by trusted certificate.\n");
|
---|
4897 |
|
---|
4898 | /*
|
---|
4899 | * Standard code signing capabilites required.
|
---|
4900 | */
|
---|
4901 | int rc = RTCrPkcs7VerifyCertCallbackCodeSigning(pCert, hCertPaths, fFlags, NULL, pErrInfo);
|
---|
4902 | if ( RT_SUCCESS(rc)
|
---|
4903 | && (fFlags & RTCRPKCS7VCC_F_SIGNED_DATA))
|
---|
4904 | {
|
---|
4905 | /*
|
---|
4906 | * If windows kernel signing, a valid certificate path must be anchored
|
---|
4907 | * by the microsoft kernel signing root certificate. The only
|
---|
4908 | * alternative is test signing.
|
---|
4909 | */
|
---|
4910 | if ( pState->fKernel
|
---|
4911 | && hCertPaths != NIL_RTCRX509CERTPATHS
|
---|
4912 | && pState->enmSignType == VERIFYEXESTATE::kSignType_Windows)
|
---|
4913 | {
|
---|
4914 | uint32_t cFound = 0;
|
---|
4915 | uint32_t cValid = 0;
|
---|
4916 | for (uint32_t iPath = 0; iPath < cPaths; iPath++)
|
---|
4917 | {
|
---|
4918 | bool fTrusted;
|
---|
4919 | PCRTCRX509NAME pSubject;
|
---|
4920 | PCRTCRX509SUBJECTPUBLICKEYINFO pPublicKeyInfo;
|
---|
4921 | int rcVerify;
|
---|
4922 | rc = RTCrX509CertPathsQueryPathInfo(hCertPaths, iPath, &fTrusted, NULL /*pcNodes*/, &pSubject, &pPublicKeyInfo,
|
---|
4923 | NULL, NULL /*pCertCtx*/, &rcVerify);
|
---|
4924 | AssertRCBreak(rc);
|
---|
4925 |
|
---|
4926 | if (RT_SUCCESS(rcVerify))
|
---|
4927 | {
|
---|
4928 | Assert(fTrusted);
|
---|
4929 | cValid++;
|
---|
4930 |
|
---|
4931 | /* Search the kernel signing root store for a matching anchor. */
|
---|
4932 | RTCRSTORECERTSEARCH Search;
|
---|
4933 | rc = RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280(pState->KernelRootStore.m_hStore, pSubject, &Search);
|
---|
4934 | AssertRCBreak(rc);
|
---|
4935 | PCRTCRCERTCTX pCertCtx;
|
---|
4936 | while ((pCertCtx = RTCrStoreCertSearchNext(pState->KernelRootStore.m_hStore, &Search)) != NULL)
|
---|
4937 | {
|
---|
4938 | PCRTCRX509SUBJECTPUBLICKEYINFO pPubKeyInfo;
|
---|
4939 | if (pCertCtx->pCert)
|
---|
4940 | pPubKeyInfo = &pCertCtx->pCert->TbsCertificate.SubjectPublicKeyInfo;
|
---|
4941 | else if (pCertCtx->pTaInfo)
|
---|
4942 | pPubKeyInfo = &pCertCtx->pTaInfo->PubKey;
|
---|
4943 | else
|
---|
4944 | pPubKeyInfo = NULL;
|
---|
4945 | if (RTCrX509SubjectPublicKeyInfo_Compare(pPubKeyInfo, pPublicKeyInfo) == 0)
|
---|
4946 | cFound++;
|
---|
4947 | RTCrCertCtxRelease(pCertCtx);
|
---|
4948 | }
|
---|
4949 |
|
---|
4950 | int rc2 = RTCrStoreCertSearchDestroy(pState->KernelRootStore.m_hStore, &Search); AssertRC(rc2);
|
---|
4951 | }
|
---|
4952 | }
|
---|
4953 | if (RT_SUCCESS(rc) && cFound == 0)
|
---|
4954 | rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE, "Not valid kernel code signature.");
|
---|
4955 | if (RT_SUCCESS(rc) && cValid != 2)
|
---|
4956 | RTMsgWarning("%u valid paths, expected 2", cValid);
|
---|
4957 | }
|
---|
4958 | /*
|
---|
4959 | * For Mac OS X signing, check for special developer ID attributes.
|
---|
4960 | */
|
---|
4961 | else if (pState->enmSignType == VERIFYEXESTATE::kSignType_OSX)
|
---|
4962 | {
|
---|
4963 | uint32_t cDevIdApp = 0;
|
---|
4964 | uint32_t cDevIdKext = 0;
|
---|
4965 | uint32_t cDevIdMacDev = 0;
|
---|
4966 | for (uint32_t i = 0; i < pCert->TbsCertificate.T3.Extensions.cItems; i++)
|
---|
4967 | {
|
---|
4968 | PCRTCRX509EXTENSION pExt = pCert->TbsCertificate.T3.Extensions.papItems[i];
|
---|
4969 | if (RTAsn1ObjId_CompareWithString(&pExt->ExtnId, RTCR_APPLE_CS_DEVID_APPLICATION_OID) == 0)
|
---|
4970 | {
|
---|
4971 | cDevIdApp++;
|
---|
4972 | if (!pExt->Critical.fValue)
|
---|
4973 | rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
|
---|
4974 | "Dev ID Application certificate extension is not flagged critical");
|
---|
4975 | }
|
---|
4976 | else if (RTAsn1ObjId_CompareWithString(&pExt->ExtnId, RTCR_APPLE_CS_DEVID_KEXT_OID) == 0)
|
---|
4977 | {
|
---|
4978 | cDevIdKext++;
|
---|
4979 | if (!pExt->Critical.fValue)
|
---|
4980 | rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
|
---|
4981 | "Dev ID kext certificate extension is not flagged critical");
|
---|
4982 | }
|
---|
4983 | else if (RTAsn1ObjId_CompareWithString(&pExt->ExtnId, RTCR_APPLE_CS_DEVID_MAC_SW_DEV_OID) == 0)
|
---|
4984 | {
|
---|
4985 | cDevIdMacDev++;
|
---|
4986 | if (!pExt->Critical.fValue)
|
---|
4987 | rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
|
---|
4988 | "Dev ID Mac SW dev certificate extension is not flagged critical");
|
---|
4989 | }
|
---|
4990 | }
|
---|
4991 | if (cDevIdApp == 0)
|
---|
4992 | {
|
---|
4993 | if (cDevIdMacDev == 0)
|
---|
4994 | rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
|
---|
4995 | "Certificate is missing the 'Dev ID Application' extension");
|
---|
4996 | else
|
---|
4997 | RTMsgWarning("Mac SW dev certificate used to sign code.");
|
---|
4998 | }
|
---|
4999 | if (cDevIdKext == 0 && pState->fKernel)
|
---|
5000 | {
|
---|
5001 | if (cDevIdMacDev == 0)
|
---|
5002 | rc = RTErrInfoSetF(pErrInfo, VERR_GENERAL_FAILURE,
|
---|
5003 | "Certificate is missing the 'Dev ID kext' extension");
|
---|
5004 | else
|
---|
5005 | RTMsgWarning("Mac SW dev certificate used to sign kernel code.");
|
---|
5006 | }
|
---|
5007 | }
|
---|
5008 | }
|
---|
5009 |
|
---|
5010 | return rc;
|
---|
5011 | }
|
---|
5012 |
|
---|
5013 | /** @callback_method_impl{FNRTLDRVALIDATESIGNEDDATA} */
|
---|
5014 | static DECLCALLBACK(int) VerifyExeCallback(RTLDRMOD hLdrMod, PCRTLDRSIGNATUREINFO pInfo, PRTERRINFO pErrInfo, void *pvUser)
|
---|
5015 | {
|
---|
5016 | VERIFYEXESTATE *pState = (VERIFYEXESTATE *)pvUser;
|
---|
5017 | RT_NOREF_PV(hLdrMod);
|
---|
5018 |
|
---|
5019 | switch (pInfo->enmType)
|
---|
5020 | {
|
---|
5021 | case RTLDRSIGNATURETYPE_PKCS7_SIGNED_DATA:
|
---|
5022 | {
|
---|
5023 | PCRTCRPKCS7CONTENTINFO pContentInfo = (PCRTCRPKCS7CONTENTINFO)pInfo->pvSignature;
|
---|
5024 |
|
---|
5025 | if (pState->cVerbose > 0)
|
---|
5026 | RTMsgInfo("Verifying '%s' signature #%u ...\n", pState->pszFilename, pInfo->iSignature + 1);
|
---|
5027 |
|
---|
5028 | /*
|
---|
5029 | * Dump the signed data if so requested and it's the first one, assuming that
|
---|
5030 | * additional signatures in contained wihtin the same ContentInfo structure.
|
---|
5031 | */
|
---|
5032 | if (pState->cVerbose > 1 && pInfo->iSignature == 0)
|
---|
5033 | RTAsn1Dump(&pContentInfo->SeqCore.Asn1Core, 0, 0, RTStrmDumpPrintfV, g_pStdOut);
|
---|
5034 |
|
---|
5035 | /*
|
---|
5036 | * We'll try different alternative timestamps here.
|
---|
5037 | */
|
---|
5038 | struct { RTTIMESPEC TimeSpec; const char *pszDesc; } aTimes[3];
|
---|
5039 | unsigned cTimes = 0;
|
---|
5040 |
|
---|
5041 | /* The specified timestamp. */
|
---|
5042 | if (RTTimeSpecGetSeconds(&pState->ValidationTime) != 0)
|
---|
5043 | {
|
---|
5044 | aTimes[cTimes].TimeSpec = pState->ValidationTime;
|
---|
5045 | aTimes[cTimes].pszDesc = "validation time";
|
---|
5046 | cTimes++;
|
---|
5047 | }
|
---|
5048 |
|
---|
5049 | /* Linking timestamp: */
|
---|
5050 | uint64_t uLinkingTime = 0;
|
---|
5051 | int rc = RTLdrQueryProp(hLdrMod, RTLDRPROP_TIMESTAMP_SECONDS, &uLinkingTime, sizeof(uLinkingTime));
|
---|
5052 | if (RT_SUCCESS(rc))
|
---|
5053 | {
|
---|
5054 | RTTimeSpecSetSeconds(&aTimes[cTimes].TimeSpec, uLinkingTime);
|
---|
5055 | aTimes[cTimes].pszDesc = "at link time";
|
---|
5056 | cTimes++;
|
---|
5057 | }
|
---|
5058 | else if (rc != VERR_NOT_FOUND)
|
---|
5059 | RTMsgError("RTLdrQueryProp/RTLDRPROP_TIMESTAMP_SECONDS failed on '%s': %Rrc\n", pState->pszFilename, rc);
|
---|
5060 |
|
---|
5061 | /* Now: */
|
---|
5062 | RTTimeNow(&aTimes[cTimes].TimeSpec);
|
---|
5063 | aTimes[cTimes].pszDesc = "now";
|
---|
5064 | cTimes++;
|
---|
5065 |
|
---|
5066 | /*
|
---|
5067 | * Do the actual verification.
|
---|
5068 | */
|
---|
5069 | for (unsigned iTime = 0; iTime < cTimes; iTime++)
|
---|
5070 | {
|
---|
5071 | if (pInfo->pvExternalData)
|
---|
5072 | rc = RTCrPkcs7VerifySignedDataWithExternalData(pContentInfo,
|
---|
5073 | RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY
|
---|
5074 | | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT
|
---|
5075 | | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT
|
---|
5076 | | RTCRPKCS7VERIFY_SD_F_CHECK_TRUST_ANCHORS,
|
---|
5077 | pState->AdditionalStore.m_hStore, pState->RootStore.m_hStore,
|
---|
5078 | &aTimes[iTime].TimeSpec,
|
---|
5079 | VerifyExecCertVerifyCallback, pState,
|
---|
5080 | pInfo->pvExternalData, pInfo->cbExternalData, pErrInfo);
|
---|
5081 | else
|
---|
5082 | rc = RTCrPkcs7VerifySignedData(pContentInfo,
|
---|
5083 | RTCRPKCS7VERIFY_SD_F_COUNTER_SIGNATURE_SIGNING_TIME_ONLY
|
---|
5084 | | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_SIGNING_TIME_IF_PRESENT
|
---|
5085 | | RTCRPKCS7VERIFY_SD_F_ALWAYS_USE_MS_TIMESTAMP_IF_PRESENT
|
---|
5086 | | RTCRPKCS7VERIFY_SD_F_CHECK_TRUST_ANCHORS,
|
---|
5087 | pState->AdditionalStore.m_hStore, pState->RootStore.m_hStore,
|
---|
5088 | &aTimes[iTime].TimeSpec,
|
---|
5089 | VerifyExecCertVerifyCallback, pState, pErrInfo);
|
---|
5090 | if (RT_SUCCESS(rc))
|
---|
5091 | {
|
---|
5092 | Assert(rc == VINF_SUCCESS || rc == VINF_CR_DIGEST_DEPRECATED);
|
---|
5093 | const char *pszNote = rc == VINF_CR_DIGEST_DEPRECATED ? " (deprecated digest)" : "";
|
---|
5094 | if (pInfo->cSignatures == 1)
|
---|
5095 | RTMsgInfo("'%s' is valid %s%s.\n", pState->pszFilename, aTimes[iTime].pszDesc, pszNote);
|
---|
5096 | else
|
---|
5097 | RTMsgInfo("'%s' signature #%u is valid %s%s.\n",
|
---|
5098 | pState->pszFilename, pInfo->iSignature + 1, aTimes[iTime].pszDesc, pszNote);
|
---|
5099 | pState->cOkay++;
|
---|
5100 | return VINF_SUCCESS;
|
---|
5101 | }
|
---|
5102 | if (rc != VERR_CR_X509_CPV_NOT_VALID_AT_TIME)
|
---|
5103 | {
|
---|
5104 | if (pInfo->cSignatures == 1)
|
---|
5105 | RTMsgError("%s: Failed to verify signature: %Rrc%#RTeim\n", pState->pszFilename, rc, pErrInfo);
|
---|
5106 | else
|
---|
5107 | RTMsgError("%s: Failed to verify signature #%u: %Rrc%#RTeim\n",
|
---|
5108 | pState->pszFilename, pInfo->iSignature + 1, rc, pErrInfo);
|
---|
5109 | pState->cBad++;
|
---|
5110 | return VINF_SUCCESS;
|
---|
5111 | }
|
---|
5112 | }
|
---|
5113 |
|
---|
5114 | if (pInfo->cSignatures == 1)
|
---|
5115 | RTMsgError("%s: Signature is not valid at present or link time.\n", pState->pszFilename);
|
---|
5116 | else
|
---|
5117 | RTMsgError("%s: Signature #%u is not valid at present or link time.\n",
|
---|
5118 | pState->pszFilename, pInfo->iSignature + 1);
|
---|
5119 | pState->cBad++;
|
---|
5120 | return VINF_SUCCESS;
|
---|
5121 | }
|
---|
5122 |
|
---|
5123 | default:
|
---|
5124 | return RTErrInfoSetF(pErrInfo, VERR_NOT_SUPPORTED, "Unsupported signature type: %d", pInfo->enmType);
|
---|
5125 | }
|
---|
5126 | }
|
---|
5127 |
|
---|
5128 | /**
|
---|
5129 | * Worker for HandleVerifyExe.
|
---|
5130 | */
|
---|
5131 | static RTEXITCODE HandleVerifyExeWorker(VERIFYEXESTATE *pState, const char *pszFilename, PRTERRINFOSTATIC pStaticErrInfo)
|
---|
5132 | {
|
---|
5133 | /*
|
---|
5134 | * Open the executable image and verify it.
|
---|
5135 | */
|
---|
5136 | RTLDRMOD hLdrMod;
|
---|
5137 | int rc = RTLdrOpen(pszFilename, RTLDR_O_FOR_VALIDATION, pState->enmLdrArch, &hLdrMod);
|
---|
5138 | if (RT_FAILURE(rc))
|
---|
5139 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error opening executable image '%s': %Rrc", pszFilename, rc);
|
---|
5140 |
|
---|
5141 | /* Reset the state. */
|
---|
5142 | pState->cBad = 0;
|
---|
5143 | pState->cOkay = 0;
|
---|
5144 | pState->pszFilename = pszFilename;
|
---|
5145 |
|
---|
5146 | rc = RTLdrVerifySignature(hLdrMod, VerifyExeCallback, pState, RTErrInfoInitStatic(pStaticErrInfo));
|
---|
5147 | if (RT_FAILURE(rc))
|
---|
5148 | RTMsgError("RTLdrVerifySignature failed on '%s': %Rrc - %s\n", pszFilename, rc, pStaticErrInfo->szMsg);
|
---|
5149 |
|
---|
5150 | int rc2 = RTLdrClose(hLdrMod);
|
---|
5151 | if (RT_FAILURE(rc2))
|
---|
5152 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTLdrClose failed: %Rrc\n", rc2);
|
---|
5153 | if (RT_FAILURE(rc))
|
---|
5154 | return rc != VERR_LDRVI_NOT_SIGNED ? RTEXITCODE_FAILURE : RTEXITCODE_SKIPPED;
|
---|
5155 |
|
---|
5156 | return pState->cOkay > 0 ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
|
---|
5157 | }
|
---|
5158 |
|
---|
5159 |
|
---|
5160 | static RTEXITCODE HandleVerifyExe(int cArgs, char **papszArgs)
|
---|
5161 | {
|
---|
5162 | RTERRINFOSTATIC StaticErrInfo;
|
---|
5163 |
|
---|
5164 | /*
|
---|
5165 | * Parse arguments.
|
---|
5166 | */
|
---|
5167 | static const RTGETOPTDEF s_aOptions[] =
|
---|
5168 | {
|
---|
5169 | { "--kernel", 'k', RTGETOPT_REQ_NOTHING },
|
---|
5170 | { "--root", 'r', RTGETOPT_REQ_STRING },
|
---|
5171 | { "--self-signed-roots-from-system", 'R', RTGETOPT_REQ_NOTHING },
|
---|
5172 | { "--additional", 'a', RTGETOPT_REQ_STRING },
|
---|
5173 | { "--add", 'a', RTGETOPT_REQ_STRING },
|
---|
5174 | { "--type", 't', RTGETOPT_REQ_STRING },
|
---|
5175 | { "--validation-time", 'T', RTGETOPT_REQ_STRING },
|
---|
5176 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
5177 | { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
|
---|
5178 | };
|
---|
5179 |
|
---|
5180 | VERIFYEXESTATE State;
|
---|
5181 | int rc = RTCrStoreCreateInMem(&State.RootStore.m_hStore, 0);
|
---|
5182 | if (RT_SUCCESS(rc))
|
---|
5183 | rc = RTCrStoreCreateInMem(&State.KernelRootStore.m_hStore, 0);
|
---|
5184 | if (RT_SUCCESS(rc))
|
---|
5185 | rc = RTCrStoreCreateInMem(&State.AdditionalStore.m_hStore, 0);
|
---|
5186 | if (RT_FAILURE(rc))
|
---|
5187 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error creating in-memory certificate store: %Rrc", rc);
|
---|
5188 |
|
---|
5189 | RTGETOPTSTATE GetState;
|
---|
5190 | rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
5191 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
5192 | RTGETOPTUNION ValueUnion;
|
---|
5193 | int ch;
|
---|
5194 | while ((ch = RTGetOpt(&GetState, &ValueUnion)) && ch != VINF_GETOPT_NOT_OPTION)
|
---|
5195 | {
|
---|
5196 | switch (ch)
|
---|
5197 | {
|
---|
5198 | case 'a':
|
---|
5199 | if (!State.AdditionalStore.addFromFile(ValueUnion.psz, &StaticErrInfo))
|
---|
5200 | return RTEXITCODE_FAILURE;
|
---|
5201 | break;
|
---|
5202 |
|
---|
5203 | case 'r':
|
---|
5204 | if (!State.RootStore.addFromFile(ValueUnion.psz, &StaticErrInfo))
|
---|
5205 | return RTEXITCODE_FAILURE;
|
---|
5206 | break;
|
---|
5207 |
|
---|
5208 | case 'R':
|
---|
5209 | if (!State.RootStore.addSelfSignedRootsFromSystem(&StaticErrInfo))
|
---|
5210 | return RTEXITCODE_FAILURE;
|
---|
5211 | break;
|
---|
5212 |
|
---|
5213 | case 't':
|
---|
5214 | if (!strcmp(ValueUnion.psz, "win") || !strcmp(ValueUnion.psz, "windows"))
|
---|
5215 | State.enmSignType = VERIFYEXESTATE::kSignType_Windows;
|
---|
5216 | else if (!strcmp(ValueUnion.psz, "osx") || !strcmp(ValueUnion.psz, "apple"))
|
---|
5217 | State.enmSignType = VERIFYEXESTATE::kSignType_OSX;
|
---|
5218 | else
|
---|
5219 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Unknown signing type: '%s'", ValueUnion.psz);
|
---|
5220 | break;
|
---|
5221 |
|
---|
5222 | case 'T':
|
---|
5223 | if (!RTTimeSpecFromString(&State.ValidationTime, ValueUnion.psz))
|
---|
5224 | return RTMsgErrorExit(RTEXITCODE_SYNTAX, "Invalid validation time (%s): %Rrc", ValueUnion.psz, rc);
|
---|
5225 | break;
|
---|
5226 |
|
---|
5227 | case 'k': State.fKernel = true; break;
|
---|
5228 | case 'v': State.cVerbose++; break;
|
---|
5229 | case 'q': State.cVerbose = 0; break;
|
---|
5230 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
5231 | case 'h': return HelpVerifyExe(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
5232 | default: return RTGetOptPrintError(ch, &ValueUnion);
|
---|
5233 | }
|
---|
5234 | }
|
---|
5235 | if (ch != VINF_GETOPT_NOT_OPTION)
|
---|
5236 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");
|
---|
5237 |
|
---|
5238 | /*
|
---|
5239 | * Populate the certificate stores according to the signing type.
|
---|
5240 | */
|
---|
5241 | # ifdef VBOX
|
---|
5242 | unsigned cSets = 0;
|
---|
5243 | struct STSTORESET aSets[6];
|
---|
5244 | switch (State.enmSignType)
|
---|
5245 | {
|
---|
5246 | case VERIFYEXESTATE::kSignType_Windows:
|
---|
5247 | aSets[cSets].hStore = State.RootStore.m_hStore;
|
---|
5248 | aSets[cSets].paTAs = g_aSUPTimestampTAs;
|
---|
5249 | aSets[cSets].cTAs = g_cSUPTimestampTAs;
|
---|
5250 | cSets++;
|
---|
5251 | aSets[cSets].hStore = State.RootStore.m_hStore;
|
---|
5252 | aSets[cSets].paTAs = g_aSUPSpcRootTAs;
|
---|
5253 | aSets[cSets].cTAs = g_cSUPSpcRootTAs;
|
---|
5254 | cSets++;
|
---|
5255 | aSets[cSets].hStore = State.RootStore.m_hStore;
|
---|
5256 | aSets[cSets].paTAs = g_aSUPNtKernelRootTAs;
|
---|
5257 | aSets[cSets].cTAs = g_cSUPNtKernelRootTAs;
|
---|
5258 | cSets++;
|
---|
5259 | aSets[cSets].hStore = State.KernelRootStore.m_hStore;
|
---|
5260 | aSets[cSets].paTAs = g_aSUPNtKernelRootTAs;
|
---|
5261 | aSets[cSets].cTAs = g_cSUPNtKernelRootTAs;
|
---|
5262 | cSets++;
|
---|
5263 | break;
|
---|
5264 |
|
---|
5265 | case VERIFYEXESTATE::kSignType_OSX:
|
---|
5266 | aSets[cSets].hStore = State.RootStore.m_hStore;
|
---|
5267 | aSets[cSets].paTAs = g_aSUPAppleRootTAs;
|
---|
5268 | aSets[cSets].cTAs = g_cSUPAppleRootTAs;
|
---|
5269 | cSets++;
|
---|
5270 | break;
|
---|
5271 | }
|
---|
5272 | for (unsigned i = 0; i < cSets; i++)
|
---|
5273 | for (unsigned j = 0; j < aSets[i].cTAs; j++)
|
---|
5274 | {
|
---|
5275 | rc = RTCrStoreCertAddEncoded(aSets[i].hStore, RTCRCERTCTX_F_ENC_TAF_DER, aSets[i].paTAs[j].pch,
|
---|
5276 | aSets[i].paTAs[j].cb, RTErrInfoInitStatic(&StaticErrInfo));
|
---|
5277 | if (RT_FAILURE(rc))
|
---|
5278 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTCrStoreCertAddEncoded failed (%u/%u): %s",
|
---|
5279 | i, j, StaticErrInfo.szMsg);
|
---|
5280 | }
|
---|
5281 | # endif /* VBOX */
|
---|
5282 |
|
---|
5283 | /*
|
---|
5284 | * Do it.
|
---|
5285 | */
|
---|
5286 | RTEXITCODE rcExit;
|
---|
5287 | for (;;)
|
---|
5288 | {
|
---|
5289 | rcExit = HandleVerifyExeWorker(&State, ValueUnion.psz, &StaticErrInfo);
|
---|
5290 | if (rcExit != RTEXITCODE_SUCCESS)
|
---|
5291 | break;
|
---|
5292 |
|
---|
5293 | /*
|
---|
5294 | * Next file
|
---|
5295 | */
|
---|
5296 | ch = RTGetOpt(&GetState, &ValueUnion);
|
---|
5297 | if (ch == 0)
|
---|
5298 | break;
|
---|
5299 | if (ch != VINF_GETOPT_NOT_OPTION)
|
---|
5300 | {
|
---|
5301 | rcExit = RTGetOptPrintError(ch, &ValueUnion);
|
---|
5302 | break;
|
---|
5303 | }
|
---|
5304 | }
|
---|
5305 |
|
---|
5306 | return rcExit;
|
---|
5307 | }
|
---|
5308 |
|
---|
5309 | #endif /* !IPRT_IN_BUILD_TOOL */
|
---|
5310 |
|
---|
5311 | /*
|
---|
5312 | * common code for show-exe and show-cat:
|
---|
5313 | */
|
---|
5314 |
|
---|
5315 | /**
|
---|
5316 | * Display an object ID.
|
---|
5317 | *
|
---|
5318 | * @returns IPRT status code.
|
---|
5319 | * @param pThis The show exe instance data.
|
---|
5320 | * @param pObjId The object ID to display.
|
---|
5321 | * @param pszLabel The field label (prefixed by szPrefix).
|
---|
5322 | * @param pszPost What to print after the ID (typically newline).
|
---|
5323 | */
|
---|
5324 | static void HandleShowExeWorkerDisplayObjId(PSHOWEXEPKCS7 pThis, PCRTASN1OBJID pObjId, const char *pszLabel, const char *pszPost)
|
---|
5325 | {
|
---|
5326 | int rc = RTAsn1QueryObjIdName(pObjId, pThis->szTmp, sizeof(pThis->szTmp));
|
---|
5327 | if (RT_SUCCESS(rc))
|
---|
5328 | {
|
---|
5329 | if (pThis->cVerbosity > 1)
|
---|
5330 | RTPrintf("%s%s%s (%s)%s", pThis->szPrefix, pszLabel, pThis->szTmp, pObjId->szObjId, pszPost);
|
---|
5331 | else
|
---|
5332 | RTPrintf("%s%s%s%s", pThis->szPrefix, pszLabel, pThis->szTmp, pszPost);
|
---|
5333 | }
|
---|
5334 | else
|
---|
5335 | RTPrintf("%s%s%s%s", pThis->szPrefix, pszLabel, pObjId->szObjId, pszPost);
|
---|
5336 | }
|
---|
5337 |
|
---|
5338 |
|
---|
5339 | /**
|
---|
5340 | * Display an object ID, without prefix and label
|
---|
5341 | *
|
---|
5342 | * @returns IPRT status code.
|
---|
5343 | * @param pThis The show exe instance data.
|
---|
5344 | * @param pObjId The object ID to display.
|
---|
5345 | * @param pszPost What to print after the ID (typically newline).
|
---|
5346 | */
|
---|
5347 | static void HandleShowExeWorkerDisplayObjIdSimple(PSHOWEXEPKCS7 pThis, PCRTASN1OBJID pObjId, const char *pszPost)
|
---|
5348 | {
|
---|
5349 | int rc = RTAsn1QueryObjIdName(pObjId, pThis->szTmp, sizeof(pThis->szTmp));
|
---|
5350 | if (RT_SUCCESS(rc))
|
---|
5351 | {
|
---|
5352 | if (pThis->cVerbosity > 1)
|
---|
5353 | RTPrintf("%s (%s)%s", pThis->szTmp, pObjId->szObjId, pszPost);
|
---|
5354 | else
|
---|
5355 | RTPrintf("%s%s", pThis->szTmp, pszPost);
|
---|
5356 | }
|
---|
5357 | else
|
---|
5358 | RTPrintf("%s%s", pObjId->szObjId, pszPost);
|
---|
5359 | }
|
---|
5360 |
|
---|
5361 |
|
---|
5362 | /**
|
---|
5363 | * Display a signer info attribute.
|
---|
5364 | *
|
---|
5365 | * @returns IPRT status code.
|
---|
5366 | * @param pThis The show exe instance data.
|
---|
5367 | * @param offPrefix The current prefix offset.
|
---|
5368 | * @param pAttr The attribute to display.
|
---|
5369 | */
|
---|
5370 | static int HandleShowExeWorkerPkcs7DisplayAttrib(PSHOWEXEPKCS7 pThis, size_t offPrefix, PCRTCRPKCS7ATTRIBUTE pAttr)
|
---|
5371 | {
|
---|
5372 | HandleShowExeWorkerDisplayObjId(pThis, &pAttr->Type, "", ":\n");
|
---|
5373 | if (pThis->cVerbosity > 4 && pAttr->SeqCore.Asn1Core.uData.pu8)
|
---|
5374 | RTPrintf("%s uData.pu8=%p cb=%#x\n", pThis->szPrefix, pAttr->SeqCore.Asn1Core.uData.pu8, pAttr->SeqCore.Asn1Core.cb);
|
---|
5375 |
|
---|
5376 | int rc = VINF_SUCCESS;
|
---|
5377 | switch (pAttr->enmType)
|
---|
5378 | {
|
---|
5379 | case RTCRPKCS7ATTRIBUTETYPE_UNKNOWN:
|
---|
5380 | if (pAttr->uValues.pCores->cItems <= 1)
|
---|
5381 | RTPrintf("%s %u bytes\n", pThis->szPrefix,pAttr->uValues.pCores->SetCore.Asn1Core.cb);
|
---|
5382 | else
|
---|
5383 | RTPrintf("%s %u bytes divided by %u items\n", pThis->szPrefix, pAttr->uValues.pCores->SetCore.Asn1Core.cb, pAttr->uValues.pCores->cItems);
|
---|
5384 | break;
|
---|
5385 |
|
---|
5386 | /* Object IDs, use pObjIds. */
|
---|
5387 | case RTCRPKCS7ATTRIBUTETYPE_OBJ_IDS:
|
---|
5388 | if (pAttr->uValues.pObjIds->cItems != 1)
|
---|
5389 | RTPrintf("%s%u object IDs:", pThis->szPrefix, pAttr->uValues.pObjIds->cItems);
|
---|
5390 | for (unsigned i = 0; i < pAttr->uValues.pObjIds->cItems; i++)
|
---|
5391 | {
|
---|
5392 | if (pAttr->uValues.pObjIds->cItems == 1)
|
---|
5393 | RTPrintf("%s ", pThis->szPrefix);
|
---|
5394 | else
|
---|
5395 | RTPrintf("%s ObjId[%u]: ", pThis->szPrefix, i);
|
---|
5396 | HandleShowExeWorkerDisplayObjIdSimple(pThis, pAttr->uValues.pObjIds->papItems[i], "\n");
|
---|
5397 | }
|
---|
5398 | break;
|
---|
5399 |
|
---|
5400 | /* Sequence of object IDs, use pObjIdSeqs. */
|
---|
5401 | case RTCRPKCS7ATTRIBUTETYPE_MS_STATEMENT_TYPE:
|
---|
5402 | if (pAttr->uValues.pObjIdSeqs->cItems != 1)
|
---|
5403 | RTPrintf("%s%u object IDs:", pThis->szPrefix, pAttr->uValues.pObjIdSeqs->cItems);
|
---|
5404 | for (unsigned i = 0; i < pAttr->uValues.pObjIdSeqs->cItems; i++)
|
---|
5405 | {
|
---|
5406 | uint32_t const cObjIds = pAttr->uValues.pObjIdSeqs->papItems[i]->cItems;
|
---|
5407 | for (unsigned j = 0; j < cObjIds; j++)
|
---|
5408 | {
|
---|
5409 | if (pAttr->uValues.pObjIdSeqs->cItems == 1)
|
---|
5410 | RTPrintf("%s ", pThis->szPrefix);
|
---|
5411 | else
|
---|
5412 | RTPrintf("%s ObjIdSeq[%u]: ", pThis->szPrefix, i);
|
---|
5413 | if (cObjIds != 1)
|
---|
5414 | RTPrintf(" ObjId[%u]: ", j);
|
---|
5415 | HandleShowExeWorkerDisplayObjIdSimple(pThis, pAttr->uValues.pObjIdSeqs->papItems[i]->papItems[i], "\n");
|
---|
5416 | }
|
---|
5417 | }
|
---|
5418 | break;
|
---|
5419 |
|
---|
5420 | /* Octet strings, use pOctetStrings. */
|
---|
5421 | case RTCRPKCS7ATTRIBUTETYPE_OCTET_STRINGS:
|
---|
5422 | if (pAttr->uValues.pOctetStrings->cItems != 1)
|
---|
5423 | RTPrintf("%s%u octet strings:", pThis->szPrefix, pAttr->uValues.pOctetStrings->cItems);
|
---|
5424 | for (unsigned i = 0; i < pAttr->uValues.pOctetStrings->cItems; i++)
|
---|
5425 | {
|
---|
5426 | PCRTASN1OCTETSTRING pOctetString = pAttr->uValues.pOctetStrings->papItems[i];
|
---|
5427 | uint32_t cbContent = pOctetString->Asn1Core.cb;
|
---|
5428 | if (cbContent > 0 && (cbContent <= 128 || pThis->cVerbosity >= 2))
|
---|
5429 | {
|
---|
5430 | uint8_t const *pbContent = pOctetString->Asn1Core.uData.pu8;
|
---|
5431 | uint32_t off = 0;
|
---|
5432 | while (off < cbContent)
|
---|
5433 | {
|
---|
5434 | uint32_t cbNow = RT_MIN(cbContent - off, 16);
|
---|
5435 | if (pAttr->uValues.pOctetStrings->cItems == 1)
|
---|
5436 | RTPrintf("%s %#06x: %.*Rhxs\n", pThis->szPrefix, off, cbNow, &pbContent[off]);
|
---|
5437 | else
|
---|
5438 | RTPrintf("%s OctetString[%u]: %#06x: %.*Rhxs\n", pThis->szPrefix, i, off, cbNow, &pbContent[off]);
|
---|
5439 | off += cbNow;
|
---|
5440 | }
|
---|
5441 | }
|
---|
5442 | else
|
---|
5443 | RTPrintf("%s: OctetString[%u]: %u bytes\n", pThis->szPrefix, i, pOctetString->Asn1Core.cb);
|
---|
5444 | }
|
---|
5445 | break;
|
---|
5446 |
|
---|
5447 | /* Counter signatures (PKCS \#9), use pCounterSignatures. */
|
---|
5448 | case RTCRPKCS7ATTRIBUTETYPE_COUNTER_SIGNATURES:
|
---|
5449 | RTPrintf("%s%u counter signatures, %u bytes in total\n", pThis->szPrefix,
|
---|
5450 | pAttr->uValues.pCounterSignatures->cItems, pAttr->uValues.pCounterSignatures->SetCore.Asn1Core.cb);
|
---|
5451 | for (uint32_t i = 0; i < pAttr->uValues.pCounterSignatures->cItems; i++)
|
---|
5452 | {
|
---|
5453 | size_t offPrefix2 = offPrefix;
|
---|
5454 | if (pAttr->uValues.pContentInfos->cItems > 1)
|
---|
5455 | offPrefix2 += RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, "CounterSig[%u]: ", i);
|
---|
5456 | else
|
---|
5457 | offPrefix2 += RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, " ");
|
---|
5458 |
|
---|
5459 | int rc2 = HandleShowExeWorkerPkcs7DisplaySignerInfo(pThis, offPrefix2,
|
---|
5460 | pAttr->uValues.pCounterSignatures->papItems[i]);
|
---|
5461 | if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
|
---|
5462 | rc = rc2;
|
---|
5463 | }
|
---|
5464 | break;
|
---|
5465 |
|
---|
5466 | /* Signing time (PKCS \#9), use pSigningTime. */
|
---|
5467 | case RTCRPKCS7ATTRIBUTETYPE_SIGNING_TIME:
|
---|
5468 | for (uint32_t i = 0; i < pAttr->uValues.pSigningTime->cItems; i++)
|
---|
5469 | {
|
---|
5470 | PCRTASN1TIME pTime = pAttr->uValues.pSigningTime->papItems[i];
|
---|
5471 | char szTS[RTTIME_STR_LEN];
|
---|
5472 | RTTimeToString(&pTime->Time, szTS, sizeof(szTS));
|
---|
5473 | if (pAttr->uValues.pSigningTime->cItems == 1)
|
---|
5474 | RTPrintf("%s %s (%.*s)\n", pThis->szPrefix, szTS, pTime->Asn1Core.cb, pTime->Asn1Core.uData.pch);
|
---|
5475 | else
|
---|
5476 | RTPrintf("%s #%u: %s (%.*s)\n", pThis->szPrefix, i, szTS, pTime->Asn1Core.cb, pTime->Asn1Core.uData.pch);
|
---|
5477 | }
|
---|
5478 | break;
|
---|
5479 |
|
---|
5480 | /* Microsoft timestamp info (RFC-3161) signed data, use pContentInfo. */
|
---|
5481 | case RTCRPKCS7ATTRIBUTETYPE_MS_TIMESTAMP:
|
---|
5482 | case RTCRPKCS7ATTRIBUTETYPE_MS_NESTED_SIGNATURE:
|
---|
5483 | if (pAttr->uValues.pContentInfos->cItems > 1)
|
---|
5484 | RTPrintf("%s%u nested signatures, %u bytes in total\n", pThis->szPrefix,
|
---|
5485 | pAttr->uValues.pContentInfos->cItems, pAttr->uValues.pContentInfos->SetCore.Asn1Core.cb);
|
---|
5486 | for (unsigned i = 0; i < pAttr->uValues.pContentInfos->cItems; i++)
|
---|
5487 | {
|
---|
5488 | size_t offPrefix2 = offPrefix;
|
---|
5489 | if (pAttr->uValues.pContentInfos->cItems > 1)
|
---|
5490 | offPrefix2 += RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, "NestedSig[%u]: ", i);
|
---|
5491 | else
|
---|
5492 | offPrefix2 += RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, " ");
|
---|
5493 | // offPrefix2 += RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, "NestedSig: ", i);
|
---|
5494 | PCRTCRPKCS7CONTENTINFO pContentInfo = pAttr->uValues.pContentInfos->papItems[i];
|
---|
5495 | int rc2;
|
---|
5496 | if (RTCrPkcs7ContentInfo_IsSignedData(pContentInfo))
|
---|
5497 | rc2 = HandleShowExeWorkerPkcs7Display(pThis, pContentInfo->u.pSignedData, offPrefix2, pContentInfo);
|
---|
5498 | else
|
---|
5499 | rc2 = RTMsgErrorRc(VERR_ASN1_UNEXPECTED_OBJ_ID, "%sPKCS#7 content in nested signature is not 'signedData': %s",
|
---|
5500 | pThis->szPrefix, pContentInfo->ContentType.szObjId);
|
---|
5501 | if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
|
---|
5502 | rc = rc2;
|
---|
5503 | }
|
---|
5504 | break;
|
---|
5505 |
|
---|
5506 | case RTCRPKCS7ATTRIBUTETYPE_APPLE_MULTI_CD_PLIST:
|
---|
5507 | if (pAttr->uValues.pContentInfos->cItems != 1)
|
---|
5508 | RTPrintf("%s%u plists, expected only 1.\n", pThis->szPrefix, pAttr->uValues.pOctetStrings->cItems);
|
---|
5509 | for (unsigned i = 0; i < pAttr->uValues.pOctetStrings->cItems; i++)
|
---|
5510 | {
|
---|
5511 | PCRTASN1OCTETSTRING pOctetString = pAttr->uValues.pOctetStrings->papItems[i];
|
---|
5512 | size_t cbContent = pOctetString->Asn1Core.cb;
|
---|
5513 | char const *pchContent = pOctetString->Asn1Core.uData.pch;
|
---|
5514 | rc = RTStrValidateEncodingEx(pchContent, cbContent, RTSTR_VALIDATE_ENCODING_EXACT_LENGTH);
|
---|
5515 | if (RT_SUCCESS(rc))
|
---|
5516 | {
|
---|
5517 | while (cbContent > 0)
|
---|
5518 | {
|
---|
5519 | const char *pchNewLine = (const char *)memchr(pchContent, '\n', cbContent);
|
---|
5520 | size_t cchToWrite = pchNewLine ? pchNewLine - pchContent : cbContent;
|
---|
5521 | if (pAttr->uValues.pOctetStrings->cItems == 1)
|
---|
5522 | RTPrintf("%s %.*s\n", pThis->szPrefix, cchToWrite, pchContent);
|
---|
5523 | else
|
---|
5524 | RTPrintf("%s plist[%u]: %.*s\n", pThis->szPrefix, i, cchToWrite, pchContent);
|
---|
5525 | if (!pchNewLine)
|
---|
5526 | break;
|
---|
5527 | pchContent = pchNewLine + 1;
|
---|
5528 | cbContent -= cchToWrite + 1;
|
---|
5529 | }
|
---|
5530 | }
|
---|
5531 | else
|
---|
5532 | {
|
---|
5533 | if (pAttr->uValues.pContentInfos->cItems != 1)
|
---|
5534 | RTPrintf("%s: plist[%u]: Invalid UTF-8: %Rrc\n", pThis->szPrefix, i, rc);
|
---|
5535 | else
|
---|
5536 | RTPrintf("%s: Invalid UTF-8: %Rrc\n", pThis->szPrefix, rc);
|
---|
5537 | for (uint32_t off = 0; off < cbContent; off += 16)
|
---|
5538 | {
|
---|
5539 | size_t cbNow = RT_MIN(cbContent - off, 16);
|
---|
5540 | if (pAttr->uValues.pOctetStrings->cItems == 1)
|
---|
5541 | RTPrintf("%s %#06x: %.*Rhxs\n", pThis->szPrefix, off, cbNow, &pchContent[off]);
|
---|
5542 | else
|
---|
5543 | RTPrintf("%s plist[%u]: %#06x: %.*Rhxs\n", pThis->szPrefix, i, off, cbNow, &pchContent[off]);
|
---|
5544 | }
|
---|
5545 | }
|
---|
5546 | }
|
---|
5547 | break;
|
---|
5548 |
|
---|
5549 | case RTCRPKCS7ATTRIBUTETYPE_INVALID:
|
---|
5550 | RTPrintf("%sINVALID!\n", pThis->szPrefix);
|
---|
5551 | break;
|
---|
5552 | case RTCRPKCS7ATTRIBUTETYPE_NOT_PRESENT:
|
---|
5553 | RTPrintf("%sNOT PRESENT!\n", pThis->szPrefix);
|
---|
5554 | break;
|
---|
5555 | default:
|
---|
5556 | RTPrintf("%senmType=%d!\n", pThis->szPrefix, pAttr->enmType);
|
---|
5557 | break;
|
---|
5558 | }
|
---|
5559 | return rc;
|
---|
5560 | }
|
---|
5561 |
|
---|
5562 |
|
---|
5563 | /**
|
---|
5564 | * Displays a SignerInfo structure.
|
---|
5565 | *
|
---|
5566 | * @returns IPRT status code.
|
---|
5567 | * @param pThis The show exe instance data.
|
---|
5568 | * @param offPrefix The current prefix offset.
|
---|
5569 | * @param pSignerInfo The structure to display.
|
---|
5570 | */
|
---|
5571 | static int HandleShowExeWorkerPkcs7DisplaySignerInfo(PSHOWEXEPKCS7 pThis, size_t offPrefix, PCRTCRPKCS7SIGNERINFO pSignerInfo)
|
---|
5572 | {
|
---|
5573 | int rc = RTAsn1Integer_ToString(&pSignerInfo->IssuerAndSerialNumber.SerialNumber,
|
---|
5574 | pThis->szTmp, sizeof(pThis->szTmp), 0 /*fFlags*/, NULL);
|
---|
5575 | if (RT_FAILURE(rc))
|
---|
5576 | RTStrPrintf(pThis->szTmp, sizeof(pThis->szTmp), "%Rrc", rc);
|
---|
5577 | RTPrintf("%s Serial No: %s\n", pThis->szPrefix, pThis->szTmp);
|
---|
5578 |
|
---|
5579 | rc = RTCrX509Name_FormatAsString(&pSignerInfo->IssuerAndSerialNumber.Name, pThis->szTmp, sizeof(pThis->szTmp), NULL);
|
---|
5580 | if (RT_FAILURE(rc))
|
---|
5581 | RTStrPrintf(pThis->szTmp, sizeof(pThis->szTmp), "%Rrc", rc);
|
---|
5582 | RTPrintf("%s Issuer: %s\n", pThis->szPrefix, pThis->szTmp);
|
---|
5583 |
|
---|
5584 | const char *pszType = RTCrDigestTypeToName(RTCrX509AlgorithmIdentifier_GetDigestType(&pSignerInfo->DigestAlgorithm,
|
---|
5585 | true /*fPureDigestsOnly*/));
|
---|
5586 | if (!pszType)
|
---|
5587 | pszType = pSignerInfo->DigestAlgorithm.Algorithm.szObjId;
|
---|
5588 | RTPrintf("%s Digest Algorithm: %s", pThis->szPrefix, pszType);
|
---|
5589 | if (pThis->cVerbosity > 1)
|
---|
5590 | RTPrintf(" (%s)\n", pSignerInfo->DigestAlgorithm.Algorithm.szObjId);
|
---|
5591 | else
|
---|
5592 | RTPrintf("\n");
|
---|
5593 |
|
---|
5594 | HandleShowExeWorkerDisplayObjId(pThis, &pSignerInfo->DigestEncryptionAlgorithm.Algorithm,
|
---|
5595 | "Digest Encryption Algorithm: ", "\n");
|
---|
5596 |
|
---|
5597 | if (pSignerInfo->AuthenticatedAttributes.cItems == 0)
|
---|
5598 | RTPrintf("%s Authenticated Attributes: none\n", pThis->szPrefix);
|
---|
5599 | else
|
---|
5600 | {
|
---|
5601 | RTPrintf("%s Authenticated Attributes: %u item%s\n", pThis->szPrefix,
|
---|
5602 | pSignerInfo->AuthenticatedAttributes.cItems, pSignerInfo->AuthenticatedAttributes.cItems > 1 ? "s" : "");
|
---|
5603 | for (unsigned j = 0; j < pSignerInfo->AuthenticatedAttributes.cItems; j++)
|
---|
5604 | {
|
---|
5605 | PRTCRPKCS7ATTRIBUTE pAttr = pSignerInfo->AuthenticatedAttributes.papItems[j];
|
---|
5606 | size_t offPrefix3 = offPrefix+ RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix,
|
---|
5607 | " AuthAttrib[%u]: ", j);
|
---|
5608 | HandleShowExeWorkerPkcs7DisplayAttrib(pThis, offPrefix3, pAttr);
|
---|
5609 | }
|
---|
5610 | pThis->szPrefix[offPrefix] = '\0';
|
---|
5611 | }
|
---|
5612 |
|
---|
5613 | if (pSignerInfo->UnauthenticatedAttributes.cItems == 0)
|
---|
5614 | RTPrintf("%s Unauthenticated Attributes: none\n", pThis->szPrefix);
|
---|
5615 | else
|
---|
5616 | {
|
---|
5617 | RTPrintf("%s Unauthenticated Attributes: %u item%s\n", pThis->szPrefix,
|
---|
5618 | pSignerInfo->UnauthenticatedAttributes.cItems, pSignerInfo->UnauthenticatedAttributes.cItems > 1 ? "s" : "");
|
---|
5619 | for (unsigned j = 0; j < pSignerInfo->UnauthenticatedAttributes.cItems; j++)
|
---|
5620 | {
|
---|
5621 | PRTCRPKCS7ATTRIBUTE pAttr = pSignerInfo->UnauthenticatedAttributes.papItems[j];
|
---|
5622 | size_t offPrefix3 = offPrefix + RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix,
|
---|
5623 | " UnauthAttrib[%u]: ", j);
|
---|
5624 | HandleShowExeWorkerPkcs7DisplayAttrib(pThis, offPrefix3, pAttr);
|
---|
5625 | }
|
---|
5626 | pThis->szPrefix[offPrefix] = '\0';
|
---|
5627 | }
|
---|
5628 |
|
---|
5629 | /** @todo show the encrypted stuff (EncryptedDigest)? */
|
---|
5630 | return rc;
|
---|
5631 | }
|
---|
5632 |
|
---|
5633 |
|
---|
5634 | /**
|
---|
5635 | * Displays a Microsoft SPC indirect data structure.
|
---|
5636 | *
|
---|
5637 | * @returns IPRT status code.
|
---|
5638 | * @param pThis The show exe instance data.
|
---|
5639 | * @param offPrefix The current prefix offset.
|
---|
5640 | * @param pIndData The indirect data to display.
|
---|
5641 | */
|
---|
5642 | static int HandleShowExeWorkerPkcs7DisplaySpcIdirectDataContent(PSHOWEXEPKCS7 pThis, size_t offPrefix,
|
---|
5643 | PCRTCRSPCINDIRECTDATACONTENT pIndData)
|
---|
5644 | {
|
---|
5645 | /*
|
---|
5646 | * The image hash.
|
---|
5647 | */
|
---|
5648 | RTDIGESTTYPE const enmDigestType = RTCrX509AlgorithmIdentifier_GetDigestType(&pIndData->DigestInfo.DigestAlgorithm,
|
---|
5649 | true /*fPureDigestsOnly*/);
|
---|
5650 | const char *pszDigestType = RTCrDigestTypeToName(enmDigestType);
|
---|
5651 | RTPrintf("%s Digest Type: %s", pThis->szPrefix, pszDigestType);
|
---|
5652 | if (pThis->cVerbosity > 1)
|
---|
5653 | RTPrintf(" (%s)\n", pIndData->DigestInfo.DigestAlgorithm.Algorithm.szObjId);
|
---|
5654 | else
|
---|
5655 | RTPrintf("\n");
|
---|
5656 | RTPrintf("%s Digest: %.*Rhxs\n",
|
---|
5657 | pThis->szPrefix, pIndData->DigestInfo.Digest.Asn1Core.cb, pIndData->DigestInfo.Digest.Asn1Core.uData.pu8);
|
---|
5658 |
|
---|
5659 | /*
|
---|
5660 | * The data/file/url.
|
---|
5661 | */
|
---|
5662 | switch (pIndData->Data.enmType)
|
---|
5663 | {
|
---|
5664 | case RTCRSPCAAOVTYPE_PE_IMAGE_DATA:
|
---|
5665 | {
|
---|
5666 | RTPrintf("%s Data Type: PE Image Data\n", pThis->szPrefix);
|
---|
5667 | PRTCRSPCPEIMAGEDATA pPeImage = pIndData->Data.uValue.pPeImage;
|
---|
5668 | /** @todo display "Flags". */
|
---|
5669 |
|
---|
5670 | switch (pPeImage->T0.File.enmChoice)
|
---|
5671 | {
|
---|
5672 | case RTCRSPCLINKCHOICE_MONIKER:
|
---|
5673 | {
|
---|
5674 | PRTCRSPCSERIALIZEDOBJECT pMoniker = pPeImage->T0.File.u.pMoniker;
|
---|
5675 | if (RTCrSpcSerializedObject_IsPresent(pMoniker))
|
---|
5676 | {
|
---|
5677 | if (RTUuidCompareStr(pMoniker->Uuid.Asn1Core.uData.pUuid, RTCRSPCSERIALIZEDOBJECT_UUID_STR) == 0)
|
---|
5678 | {
|
---|
5679 | RTPrintf("%s Moniker: SpcSerializedObject (%RTuuid)\n",
|
---|
5680 | pThis->szPrefix, pMoniker->Uuid.Asn1Core.uData.pUuid);
|
---|
5681 |
|
---|
5682 | PCRTCRSPCSERIALIZEDOBJECTATTRIBUTES pData = pMoniker->u.pData;
|
---|
5683 | if (pData)
|
---|
5684 | for (uint32_t i = 0; i < pData->cItems; i++)
|
---|
5685 | {
|
---|
5686 | RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix,
|
---|
5687 | "MonikerAttrib[%u]: ", i);
|
---|
5688 |
|
---|
5689 | switch (pData->papItems[i]->enmType)
|
---|
5690 | {
|
---|
5691 | case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V2:
|
---|
5692 | case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1:
|
---|
5693 | {
|
---|
5694 | PCRTCRSPCSERIALIZEDPAGEHASHES pPgHashes = pData->papItems[i]->u.pPageHashes;
|
---|
5695 | uint32_t const cbHash = pData->papItems[i]->enmType
|
---|
5696 | == RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1
|
---|
5697 | ? 160/8 /*SHA-1*/ : 256/8 /*SHA-256*/;
|
---|
5698 | uint32_t const cPages = pPgHashes->RawData.Asn1Core.cb / (cbHash + sizeof(uint32_t));
|
---|
5699 |
|
---|
5700 | RTPrintf("%sPage Hashes version %u - %u pages (%u bytes total)\n", pThis->szPrefix,
|
---|
5701 | pData->papItems[i]->enmType
|
---|
5702 | == RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_PAGE_HASHES_V1 ? 1 : 2,
|
---|
5703 | cPages, pPgHashes->RawData.Asn1Core.cb);
|
---|
5704 | if (pThis->cVerbosity > 0)
|
---|
5705 | {
|
---|
5706 | PCRTCRSPCPEIMAGEPAGEHASHES pPg = pPgHashes->pData;
|
---|
5707 | for (unsigned iPg = 0; iPg < cPages; iPg++)
|
---|
5708 | {
|
---|
5709 | uint32_t offHash = 0;
|
---|
5710 | do
|
---|
5711 | {
|
---|
5712 | if (offHash == 0)
|
---|
5713 | RTPrintf("%.*s Page#%04u/%#08x: ",
|
---|
5714 | offPrefix, pThis->szPrefix, iPg, pPg->Generic.offFile);
|
---|
5715 | else
|
---|
5716 | RTPrintf("%.*s ", offPrefix, pThis->szPrefix);
|
---|
5717 | uint32_t cbLeft = cbHash - offHash;
|
---|
5718 | if (cbLeft > 24)
|
---|
5719 | cbLeft = 16;
|
---|
5720 | RTPrintf("%.*Rhxs\n", cbLeft, &pPg->Generic.abHash[offHash]);
|
---|
5721 | offHash += cbLeft;
|
---|
5722 | } while (offHash < cbHash);
|
---|
5723 | pPg = (PCRTCRSPCPEIMAGEPAGEHASHES)&pPg->Generic.abHash[cbHash];
|
---|
5724 | }
|
---|
5725 |
|
---|
5726 | if (pThis->cVerbosity > 3)
|
---|
5727 | RTPrintf("%.*Rhxd\n",
|
---|
5728 | pPgHashes->RawData.Asn1Core.cb,
|
---|
5729 | pPgHashes->RawData.Asn1Core.uData.pu8);
|
---|
5730 | }
|
---|
5731 | break;
|
---|
5732 | }
|
---|
5733 |
|
---|
5734 | case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_UNKNOWN:
|
---|
5735 | HandleShowExeWorkerDisplayObjIdSimple(pThis, &pData->papItems[i]->Type, "\n");
|
---|
5736 | break;
|
---|
5737 | case RTCRSPCSERIALIZEDOBJECTATTRIBUTETYPE_NOT_PRESENT:
|
---|
5738 | RTPrintf("%sNot present!\n", pThis->szPrefix);
|
---|
5739 | break;
|
---|
5740 | default:
|
---|
5741 | RTPrintf("%senmType=%d!\n", pThis->szPrefix, pData->papItems[i]->enmType);
|
---|
5742 | break;
|
---|
5743 | }
|
---|
5744 | pThis->szPrefix[offPrefix] = '\0';
|
---|
5745 | }
|
---|
5746 | else
|
---|
5747 | RTPrintf("%s pData is NULL!\n", pThis->szPrefix);
|
---|
5748 | }
|
---|
5749 | else
|
---|
5750 | RTPrintf("%s Moniker: Unknown UUID: %RTuuid\n",
|
---|
5751 | pThis->szPrefix, pMoniker->Uuid.Asn1Core.uData.pUuid);
|
---|
5752 | }
|
---|
5753 | else
|
---|
5754 | RTPrintf("%s Moniker: not present\n", pThis->szPrefix);
|
---|
5755 | break;
|
---|
5756 | }
|
---|
5757 |
|
---|
5758 | case RTCRSPCLINKCHOICE_URL:
|
---|
5759 | {
|
---|
5760 | const char *pszUrl = NULL;
|
---|
5761 | int rc = pPeImage->T0.File.u.pUrl
|
---|
5762 | ? RTAsn1String_QueryUtf8(pPeImage->T0.File.u.pUrl, &pszUrl, NULL)
|
---|
5763 | : VERR_NOT_FOUND;
|
---|
5764 | if (RT_SUCCESS(rc))
|
---|
5765 | RTPrintf("%s URL: '%s'\n", pThis->szPrefix, pszUrl);
|
---|
5766 | else
|
---|
5767 | RTPrintf("%s URL: rc=%Rrc\n", pThis->szPrefix, rc);
|
---|
5768 | break;
|
---|
5769 | }
|
---|
5770 |
|
---|
5771 | case RTCRSPCLINKCHOICE_FILE:
|
---|
5772 | {
|
---|
5773 | const char *pszFile = NULL;
|
---|
5774 | int rc = pPeImage->T0.File.u.pT2 && pPeImage->T0.File.u.pT2->File.u.pAscii
|
---|
5775 | ? RTAsn1String_QueryUtf8(pPeImage->T0.File.u.pT2->File.u.pAscii, &pszFile, NULL)
|
---|
5776 | : VERR_NOT_FOUND;
|
---|
5777 | if (RT_SUCCESS(rc))
|
---|
5778 | RTPrintf("%s File: '%s'\n", pThis->szPrefix, pszFile);
|
---|
5779 | else
|
---|
5780 | RTPrintf("%s File: rc=%Rrc\n", pThis->szPrefix, rc);
|
---|
5781 | if (pThis->cVerbosity > 4 && pPeImage->T0.File.u.pT2 == NULL)
|
---|
5782 | RTPrintf("%s pT2=NULL\n", pThis->szPrefix);
|
---|
5783 | else if (pThis->cVerbosity > 4)
|
---|
5784 | {
|
---|
5785 | PCRTASN1STRING pStr = pPeImage->T0.File.u.pT2->File.u.pAscii;
|
---|
5786 | RTPrintf("%s pT2=%p/%p LB %#x fFlags=%#x pOps=%p (%s)\n"
|
---|
5787 | "%s enmChoice=%d pStr=%p/%p LB %#x fFlags=%#x\n",
|
---|
5788 | pThis->szPrefix,
|
---|
5789 | pPeImage->T0.File.u.pT2,
|
---|
5790 | pPeImage->T0.File.u.pT2->CtxTag2.Asn1Core.uData.pu8,
|
---|
5791 | pPeImage->T0.File.u.pT2->CtxTag2.Asn1Core.cb,
|
---|
5792 | pPeImage->T0.File.u.pT2->CtxTag2.Asn1Core.fFlags,
|
---|
5793 | pPeImage->T0.File.u.pT2->CtxTag2.Asn1Core.pOps,
|
---|
5794 | pPeImage->T0.File.u.pT2->CtxTag2.Asn1Core.pOps
|
---|
5795 | ? pPeImage->T0.File.u.pT2->CtxTag2.Asn1Core.pOps->pszName : "",
|
---|
5796 | pThis->szPrefix,
|
---|
5797 | pPeImage->T0.File.u.pT2->File.enmChoice,
|
---|
5798 | pStr,
|
---|
5799 | pStr ? pStr->Asn1Core.uData.pu8 : NULL,
|
---|
5800 | pStr ? pStr->Asn1Core.cb : 0,
|
---|
5801 | pStr ? pStr->Asn1Core.fFlags : 0);
|
---|
5802 | }
|
---|
5803 | break;
|
---|
5804 | }
|
---|
5805 |
|
---|
5806 | case RTCRSPCLINKCHOICE_NOT_PRESENT:
|
---|
5807 | RTPrintf("%s File not present!\n", pThis->szPrefix);
|
---|
5808 | break;
|
---|
5809 | default:
|
---|
5810 | RTPrintf("%s enmChoice=%d!\n", pThis->szPrefix, pPeImage->T0.File.enmChoice);
|
---|
5811 | break;
|
---|
5812 | }
|
---|
5813 | break;
|
---|
5814 | }
|
---|
5815 |
|
---|
5816 | case RTCRSPCAAOVTYPE_UNKNOWN:
|
---|
5817 | HandleShowExeWorkerDisplayObjId(pThis, &pIndData->Data.Type, " Data Type: ", "\n");
|
---|
5818 | break;
|
---|
5819 | case RTCRSPCAAOVTYPE_NOT_PRESENT:
|
---|
5820 | RTPrintf("%s Data Type: Not present!\n", pThis->szPrefix);
|
---|
5821 | break;
|
---|
5822 | default:
|
---|
5823 | RTPrintf("%s Data Type: enmType=%d!\n", pThis->szPrefix, pIndData->Data.enmType);
|
---|
5824 | break;
|
---|
5825 | }
|
---|
5826 |
|
---|
5827 | return VINF_SUCCESS;
|
---|
5828 | }
|
---|
5829 |
|
---|
5830 |
|
---|
5831 | /**
|
---|
5832 | * Display an PKCS#7 signed data instance.
|
---|
5833 | *
|
---|
5834 | * @returns IPRT status code.
|
---|
5835 | * @param pThis The show exe instance data.
|
---|
5836 | * @param pSignedData The signed data to display.
|
---|
5837 | * @param offPrefix The current prefix offset.
|
---|
5838 | * @param pContentInfo The content info structure (for the size).
|
---|
5839 | */
|
---|
5840 | static int HandleShowExeWorkerPkcs7Display(PSHOWEXEPKCS7 pThis, PRTCRPKCS7SIGNEDDATA pSignedData, size_t offPrefix,
|
---|
5841 | PCRTCRPKCS7CONTENTINFO pContentInfo)
|
---|
5842 | {
|
---|
5843 | pThis->szPrefix[offPrefix] = '\0';
|
---|
5844 | RTPrintf("%sPKCS#7 signature: %u (%#x) bytes\n", pThis->szPrefix,
|
---|
5845 | RTASN1CORE_GET_RAW_ASN1_SIZE(&pContentInfo->SeqCore.Asn1Core),
|
---|
5846 | RTASN1CORE_GET_RAW_ASN1_SIZE(&pContentInfo->SeqCore.Asn1Core));
|
---|
5847 |
|
---|
5848 | /*
|
---|
5849 | * Display list of signing algorithms.
|
---|
5850 | */
|
---|
5851 | RTPrintf("%sDigestAlgorithms: ", pThis->szPrefix);
|
---|
5852 | if (pSignedData->DigestAlgorithms.cItems == 0)
|
---|
5853 | RTPrintf("none");
|
---|
5854 | for (unsigned i = 0; i < pSignedData->DigestAlgorithms.cItems; i++)
|
---|
5855 | {
|
---|
5856 | PCRTCRX509ALGORITHMIDENTIFIER pAlgoId = pSignedData->DigestAlgorithms.papItems[i];
|
---|
5857 | const char *pszDigestType = RTCrDigestTypeToName(RTCrX509AlgorithmIdentifier_GetDigestType(pAlgoId,
|
---|
5858 | true /*fPureDigestsOnly*/));
|
---|
5859 | if (!pszDigestType)
|
---|
5860 | pszDigestType = pAlgoId->Algorithm.szObjId;
|
---|
5861 | RTPrintf(i == 0 ? "%s" : ", %s", pszDigestType);
|
---|
5862 | if (pThis->cVerbosity > 1)
|
---|
5863 | RTPrintf(" (%s)", pAlgoId->Algorithm.szObjId);
|
---|
5864 | }
|
---|
5865 | RTPrintf("\n");
|
---|
5866 |
|
---|
5867 | /*
|
---|
5868 | * Display the signed data content.
|
---|
5869 | */
|
---|
5870 | if (RTAsn1ObjId_CompareWithString(&pSignedData->ContentInfo.ContentType, RTCRSPCINDIRECTDATACONTENT_OID) == 0)
|
---|
5871 | {
|
---|
5872 | RTPrintf("%s ContentType: SpcIndirectDataContent (" RTCRSPCINDIRECTDATACONTENT_OID ")\n", pThis->szPrefix);
|
---|
5873 | size_t offPrefix2 = RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, " SPC Ind Data: ");
|
---|
5874 | HandleShowExeWorkerPkcs7DisplaySpcIdirectDataContent(pThis, offPrefix2 + offPrefix,
|
---|
5875 | pSignedData->ContentInfo.u.pIndirectDataContent);
|
---|
5876 | pThis->szPrefix[offPrefix] = '\0';
|
---|
5877 | }
|
---|
5878 | else
|
---|
5879 | {
|
---|
5880 | HandleShowExeWorkerDisplayObjId(pThis, &pSignedData->ContentInfo.ContentType, " ContentType: ", " - not implemented.\n");
|
---|
5881 | RTPrintf("%s %u (%#x) bytes\n", pThis->szPrefix,
|
---|
5882 | pSignedData->ContentInfo.Content.Asn1Core.cb, pSignedData->ContentInfo.Content.Asn1Core.cb);
|
---|
5883 | }
|
---|
5884 |
|
---|
5885 | /*
|
---|
5886 | * Display certificates (Certificates).
|
---|
5887 | */
|
---|
5888 | if (pSignedData->Certificates.cItems > 0)
|
---|
5889 | {
|
---|
5890 | RTPrintf("%s Certificates: %u\n", pThis->szPrefix, pSignedData->Certificates.cItems);
|
---|
5891 | for (uint32_t i = 0; i < pSignedData->Certificates.cItems; i++)
|
---|
5892 | {
|
---|
5893 | PCRTCRPKCS7CERT pCert = pSignedData->Certificates.papItems[i];
|
---|
5894 | if (i != 0 && pThis->cVerbosity >= 2)
|
---|
5895 | RTPrintf("\n");
|
---|
5896 | switch (pCert->enmChoice)
|
---|
5897 | {
|
---|
5898 | case RTCRPKCS7CERTCHOICE_X509:
|
---|
5899 | {
|
---|
5900 | PCRTCRX509CERTIFICATE pX509Cert = pCert->u.pX509Cert;
|
---|
5901 | int rc2 = RTAsn1QueryObjIdName(&pX509Cert->SignatureAlgorithm.Algorithm, pThis->szTmp, sizeof(pThis->szTmp));
|
---|
5902 | RTPrintf("%s Certificate #%u: %s\n", pThis->szPrefix, i,
|
---|
5903 | RT_SUCCESS(rc2) ? pThis->szTmp : pX509Cert->SignatureAlgorithm.Algorithm.szObjId);
|
---|
5904 |
|
---|
5905 | rc2 = RTCrX509Name_FormatAsString(&pX509Cert->TbsCertificate.Subject,
|
---|
5906 | pThis->szTmp, sizeof(pThis->szTmp), NULL);
|
---|
5907 | if (RT_FAILURE(rc2))
|
---|
5908 | RTStrPrintf(pThis->szTmp, sizeof(pThis->szTmp), "%Rrc", rc2);
|
---|
5909 | RTPrintf("%s Subject: %s\n", pThis->szPrefix, pThis->szTmp);
|
---|
5910 |
|
---|
5911 | rc2 = RTCrX509Name_FormatAsString(&pX509Cert->TbsCertificate.Issuer,
|
---|
5912 | pThis->szTmp, sizeof(pThis->szTmp), NULL);
|
---|
5913 | if (RT_FAILURE(rc2))
|
---|
5914 | RTStrPrintf(pThis->szTmp, sizeof(pThis->szTmp), "%Rrc", rc2);
|
---|
5915 | RTPrintf("%s Issuer: %s\n", pThis->szPrefix, pThis->szTmp);
|
---|
5916 |
|
---|
5917 |
|
---|
5918 | char szNotAfter[RTTIME_STR_LEN];
|
---|
5919 | RTPrintf("%s Valid: %s thru %s\n", pThis->szPrefix,
|
---|
5920 | RTTimeToString(&pX509Cert->TbsCertificate.Validity.NotBefore.Time,
|
---|
5921 | pThis->szTmp, sizeof(pThis->szTmp)),
|
---|
5922 | RTTimeToString(&pX509Cert->TbsCertificate.Validity.NotAfter.Time,
|
---|
5923 | szNotAfter, sizeof(szNotAfter)));
|
---|
5924 | break;
|
---|
5925 | }
|
---|
5926 |
|
---|
5927 | default:
|
---|
5928 | RTPrintf("%s Certificate #%u: Unsupported type\n", pThis->szPrefix, i);
|
---|
5929 | break;
|
---|
5930 | }
|
---|
5931 |
|
---|
5932 |
|
---|
5933 | if (pThis->cVerbosity >= 2)
|
---|
5934 | RTAsn1Dump(RTCrPkcs7Cert_GetAsn1Core(pSignedData->Certificates.papItems[i]), 0,
|
---|
5935 | ((uint32_t)offPrefix + 9) / 2, RTStrmDumpPrintfV, g_pStdOut);
|
---|
5936 | }
|
---|
5937 |
|
---|
5938 | /** @todo display certificates properly. */
|
---|
5939 | }
|
---|
5940 |
|
---|
5941 | if (pSignedData->Crls.cb > 0)
|
---|
5942 | RTPrintf("%s CRLs: %u bytes\n", pThis->szPrefix, pSignedData->Crls.cb);
|
---|
5943 |
|
---|
5944 | /*
|
---|
5945 | * Show signatures (SignerInfos).
|
---|
5946 | */
|
---|
5947 | unsigned const cSigInfos = pSignedData->SignerInfos.cItems;
|
---|
5948 | if (cSigInfos != 1)
|
---|
5949 | RTPrintf("%s SignerInfos: %u signers\n", pThis->szPrefix, cSigInfos);
|
---|
5950 | else
|
---|
5951 | RTPrintf("%s SignerInfos:\n", pThis->szPrefix);
|
---|
5952 | int rc = VINF_SUCCESS;
|
---|
5953 | for (unsigned i = 0; i < cSigInfos; i++)
|
---|
5954 | {
|
---|
5955 | size_t offPrefix2 = offPrefix;
|
---|
5956 | if (cSigInfos != 1)
|
---|
5957 | offPrefix2 += RTStrPrintf(&pThis->szPrefix[offPrefix], sizeof(pThis->szPrefix) - offPrefix, "SignerInfo[%u]: ", i);
|
---|
5958 |
|
---|
5959 | int rc2 = HandleShowExeWorkerPkcs7DisplaySignerInfo(pThis, offPrefix2, pSignedData->SignerInfos.papItems[i]);
|
---|
5960 | if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
|
---|
5961 | rc = rc2;
|
---|
5962 | }
|
---|
5963 | pThis->szPrefix[offPrefix] = '\0';
|
---|
5964 |
|
---|
5965 | return rc;
|
---|
5966 | }
|
---|
5967 |
|
---|
5968 |
|
---|
5969 | /*
|
---|
5970 | * The 'show-exe' command.
|
---|
5971 | */
|
---|
5972 | static RTEXITCODE HelpShowExe(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
5973 | {
|
---|
5974 | RT_NOREF_PV(enmLevel);
|
---|
5975 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT, "show-exe [--verbose|-v] [--quiet|-q] <exe1> [exe2 [..]]\n");
|
---|
5976 | return RTEXITCODE_SUCCESS;
|
---|
5977 | }
|
---|
5978 |
|
---|
5979 |
|
---|
5980 | static RTEXITCODE HandleShowExe(int cArgs, char **papszArgs)
|
---|
5981 | {
|
---|
5982 | /*
|
---|
5983 | * Parse arguments.
|
---|
5984 | */
|
---|
5985 | static const RTGETOPTDEF s_aOptions[] =
|
---|
5986 | {
|
---|
5987 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
5988 | { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
|
---|
5989 | };
|
---|
5990 |
|
---|
5991 | unsigned cVerbosity = 0;
|
---|
5992 | RTLDRARCH enmLdrArch = RTLDRARCH_WHATEVER;
|
---|
5993 |
|
---|
5994 | RTGETOPTSTATE GetState;
|
---|
5995 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
5996 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
5997 | RTGETOPTUNION ValueUnion;
|
---|
5998 | int ch;
|
---|
5999 | while ((ch = RTGetOpt(&GetState, &ValueUnion)) && ch != VINF_GETOPT_NOT_OPTION)
|
---|
6000 | {
|
---|
6001 | switch (ch)
|
---|
6002 | {
|
---|
6003 | case 'v': cVerbosity++; break;
|
---|
6004 | case 'q': cVerbosity = 0; break;
|
---|
6005 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
6006 | case 'h': return HelpShowExe(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
6007 | default: return RTGetOptPrintError(ch, &ValueUnion);
|
---|
6008 | }
|
---|
6009 | }
|
---|
6010 | if (ch != VINF_GETOPT_NOT_OPTION)
|
---|
6011 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");
|
---|
6012 |
|
---|
6013 | /*
|
---|
6014 | * Do it.
|
---|
6015 | */
|
---|
6016 | unsigned iFile = 0;
|
---|
6017 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
6018 | do
|
---|
6019 | {
|
---|
6020 | RTPrintf(iFile == 0 ? "%s:\n" : "\n%s:\n", ValueUnion.psz);
|
---|
6021 |
|
---|
6022 | SHOWEXEPKCS7 This;
|
---|
6023 | RT_ZERO(This);
|
---|
6024 | This.cVerbosity = cVerbosity;
|
---|
6025 |
|
---|
6026 | RTEXITCODE rcExitThis = SignToolPkcs7Exe_InitFromFile(&This, ValueUnion.psz, cVerbosity, enmLdrArch);
|
---|
6027 | if (rcExitThis == RTEXITCODE_SUCCESS)
|
---|
6028 | {
|
---|
6029 | rc = HandleShowExeWorkerPkcs7Display(&This, This.pSignedData, 0, &This.ContentInfo);
|
---|
6030 | if (RT_FAILURE(rc))
|
---|
6031 | rcExit = RTEXITCODE_FAILURE;
|
---|
6032 | SignToolPkcs7Exe_Delete(&This);
|
---|
6033 | }
|
---|
6034 | if (rcExitThis != RTEXITCODE_SUCCESS && rcExit == RTEXITCODE_SUCCESS)
|
---|
6035 | rcExit = rcExitThis;
|
---|
6036 |
|
---|
6037 | iFile++;
|
---|
6038 | } while ((ch = RTGetOpt(&GetState, &ValueUnion)) == VINF_GETOPT_NOT_OPTION);
|
---|
6039 | if (ch != 0)
|
---|
6040 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
6041 |
|
---|
6042 | return rcExit;
|
---|
6043 | }
|
---|
6044 |
|
---|
6045 |
|
---|
6046 | /*
|
---|
6047 | * The 'show-cat' command.
|
---|
6048 | */
|
---|
6049 | static RTEXITCODE HelpShowCat(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
6050 | {
|
---|
6051 | RT_NOREF_PV(enmLevel);
|
---|
6052 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT, "show-cat [--verbose|-v] [--quiet|-q] <cat1> [cat2 [..]]\n");
|
---|
6053 | return RTEXITCODE_SUCCESS;
|
---|
6054 | }
|
---|
6055 |
|
---|
6056 |
|
---|
6057 | static RTEXITCODE HandleShowCat(int cArgs, char **papszArgs)
|
---|
6058 | {
|
---|
6059 | /*
|
---|
6060 | * Parse arguments.
|
---|
6061 | */
|
---|
6062 | static const RTGETOPTDEF s_aOptions[] =
|
---|
6063 | {
|
---|
6064 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
6065 | { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
|
---|
6066 | };
|
---|
6067 |
|
---|
6068 | unsigned cVerbosity = 0;
|
---|
6069 |
|
---|
6070 | RTGETOPTSTATE GetState;
|
---|
6071 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
6072 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
6073 | RTGETOPTUNION ValueUnion;
|
---|
6074 | int ch;
|
---|
6075 | while ((ch = RTGetOpt(&GetState, &ValueUnion)) && ch != VINF_GETOPT_NOT_OPTION)
|
---|
6076 | {
|
---|
6077 | switch (ch)
|
---|
6078 | {
|
---|
6079 | case 'v': cVerbosity++; break;
|
---|
6080 | case 'q': cVerbosity = 0; break;
|
---|
6081 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
6082 | case 'h': return HelpShowCat(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
6083 | default: return RTGetOptPrintError(ch, &ValueUnion);
|
---|
6084 | }
|
---|
6085 | }
|
---|
6086 | if (ch != VINF_GETOPT_NOT_OPTION)
|
---|
6087 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");
|
---|
6088 |
|
---|
6089 | /*
|
---|
6090 | * Do it.
|
---|
6091 | */
|
---|
6092 | unsigned iFile = 0;
|
---|
6093 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
6094 | do
|
---|
6095 | {
|
---|
6096 | RTPrintf(iFile == 0 ? "%s:\n" : "\n%s:\n", ValueUnion.psz);
|
---|
6097 |
|
---|
6098 | SHOWEXEPKCS7 This;
|
---|
6099 | RT_ZERO(This);
|
---|
6100 | This.cVerbosity = cVerbosity;
|
---|
6101 |
|
---|
6102 | RTEXITCODE rcExitThis = SignToolPkcs7_InitFromFile(&This, ValueUnion.psz, cVerbosity);
|
---|
6103 | if (rcExitThis == RTEXITCODE_SUCCESS)
|
---|
6104 | {
|
---|
6105 | This.hLdrMod = NIL_RTLDRMOD;
|
---|
6106 |
|
---|
6107 | rc = HandleShowExeWorkerPkcs7Display(&This, This.pSignedData, 0, &This.ContentInfo);
|
---|
6108 | if (RT_FAILURE(rc))
|
---|
6109 | rcExit = RTEXITCODE_FAILURE;
|
---|
6110 | SignToolPkcs7Exe_Delete(&This);
|
---|
6111 | }
|
---|
6112 | if (rcExitThis != RTEXITCODE_SUCCESS && rcExit == RTEXITCODE_SUCCESS)
|
---|
6113 | rcExit = rcExitThis;
|
---|
6114 |
|
---|
6115 | iFile++;
|
---|
6116 | } while ((ch = RTGetOpt(&GetState, &ValueUnion)) == VINF_GETOPT_NOT_OPTION);
|
---|
6117 | if (ch != 0)
|
---|
6118 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
6119 |
|
---|
6120 | return rcExit;
|
---|
6121 | }
|
---|
6122 |
|
---|
6123 |
|
---|
6124 | /*********************************************************************************************************************************
|
---|
6125 | * The 'hash-exe' command. *
|
---|
6126 | *********************************************************************************************************************************/
|
---|
6127 | static RTEXITCODE HelpHashExe(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
6128 | {
|
---|
6129 | RT_NOREF_PV(enmLevel);
|
---|
6130 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT, "hash-exe [--verbose|-v] [--quiet|-q] <exe1> [exe2 [..]]\n");
|
---|
6131 | return RTEXITCODE_SUCCESS;
|
---|
6132 | }
|
---|
6133 |
|
---|
6134 |
|
---|
6135 | static RTEXITCODE HandleHashExe(int cArgs, char **papszArgs)
|
---|
6136 | {
|
---|
6137 | /*
|
---|
6138 | * Parse arguments.
|
---|
6139 | */
|
---|
6140 | static const RTGETOPTDEF s_aOptions[] =
|
---|
6141 | {
|
---|
6142 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
6143 | { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
|
---|
6144 | };
|
---|
6145 |
|
---|
6146 | unsigned cVerbosity = 0;
|
---|
6147 | RTLDRARCH enmLdrArch = RTLDRARCH_WHATEVER;
|
---|
6148 |
|
---|
6149 | RTGETOPTSTATE GetState;
|
---|
6150 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
6151 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
6152 | RTGETOPTUNION ValueUnion;
|
---|
6153 | int ch;
|
---|
6154 | while ((ch = RTGetOpt(&GetState, &ValueUnion)) && ch != VINF_GETOPT_NOT_OPTION)
|
---|
6155 | {
|
---|
6156 | switch (ch)
|
---|
6157 | {
|
---|
6158 | case 'v': cVerbosity++; break;
|
---|
6159 | case 'q': cVerbosity = 0; break;
|
---|
6160 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
6161 | case 'h': return HelpHashExe(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
6162 | default: return RTGetOptPrintError(ch, &ValueUnion);
|
---|
6163 | }
|
---|
6164 | }
|
---|
6165 | if (ch != VINF_GETOPT_NOT_OPTION)
|
---|
6166 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No executable given.");
|
---|
6167 |
|
---|
6168 | /*
|
---|
6169 | * Do it.
|
---|
6170 | */
|
---|
6171 | unsigned iFile = 0;
|
---|
6172 | RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
|
---|
6173 | do
|
---|
6174 | {
|
---|
6175 | RTPrintf(iFile == 0 ? "%s:\n" : "\n%s:\n", ValueUnion.psz);
|
---|
6176 |
|
---|
6177 | RTERRINFOSTATIC ErrInfo;
|
---|
6178 | RTLDRMOD hLdrMod;
|
---|
6179 | rc = RTLdrOpenEx(ValueUnion.psz, RTLDR_O_FOR_VALIDATION, enmLdrArch, &hLdrMod, RTErrInfoInitStatic(&ErrInfo));
|
---|
6180 | if (RT_SUCCESS(rc))
|
---|
6181 | {
|
---|
6182 | uint8_t abHash[RTSHA512_HASH_SIZE];
|
---|
6183 | char szDigest[RTSHA512_DIGEST_LEN + 1];
|
---|
6184 |
|
---|
6185 | /* SHA-1: */
|
---|
6186 | rc = RTLdrHashImage(hLdrMod, RTDIGESTTYPE_SHA1, abHash, sizeof(abHash));
|
---|
6187 | if (RT_SUCCESS(rc))
|
---|
6188 | RTSha1ToString(abHash, szDigest, sizeof(szDigest));
|
---|
6189 | else
|
---|
6190 | RTStrPrintf(szDigest, sizeof(szDigest), "%Rrc", rc);
|
---|
6191 | RTPrintf(" SHA-1: %s\n", szDigest);
|
---|
6192 |
|
---|
6193 | /* SHA-256: */
|
---|
6194 | rc = RTLdrHashImage(hLdrMod, RTDIGESTTYPE_SHA256, abHash, sizeof(abHash));
|
---|
6195 | if (RT_SUCCESS(rc))
|
---|
6196 | RTSha256ToString(abHash, szDigest, sizeof(szDigest));
|
---|
6197 | else
|
---|
6198 | RTStrPrintf(szDigest, sizeof(szDigest), "%Rrc", rc);
|
---|
6199 | RTPrintf(" SHA-256: %s\n", szDigest);
|
---|
6200 |
|
---|
6201 | /* SHA-512: */
|
---|
6202 | rc = RTLdrHashImage(hLdrMod, RTDIGESTTYPE_SHA512, abHash, sizeof(abHash));
|
---|
6203 | if (RT_SUCCESS(rc))
|
---|
6204 | RTSha512ToString(abHash, szDigest, sizeof(szDigest));
|
---|
6205 | else
|
---|
6206 | RTStrPrintf(szDigest, sizeof(szDigest), "%Rrc", rc);
|
---|
6207 | RTPrintf(" SHA-512: %s\n", szDigest);
|
---|
6208 |
|
---|
6209 | RTLdrClose(hLdrMod);
|
---|
6210 | }
|
---|
6211 | else
|
---|
6212 | rcExit = RTMsgErrorExitFailure("Failed to open '%s': %Rrc%#RTeim", ValueUnion.psz, rc, &ErrInfo.Core);
|
---|
6213 |
|
---|
6214 | } while ((ch = RTGetOpt(&GetState, &ValueUnion)) == VINF_GETOPT_NOT_OPTION);
|
---|
6215 | if (ch != 0)
|
---|
6216 | return RTGetOptPrintError(ch, &ValueUnion);
|
---|
6217 |
|
---|
6218 | return rcExit;
|
---|
6219 | }
|
---|
6220 |
|
---|
6221 |
|
---|
6222 | /*********************************************************************************************************************************
|
---|
6223 | * The 'make-tainfo' command. *
|
---|
6224 | *********************************************************************************************************************************/
|
---|
6225 | static RTEXITCODE HelpMakeTaInfo(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
6226 | {
|
---|
6227 | RT_NOREF_PV(enmLevel);
|
---|
6228 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
6229 | "make-tainfo [--verbose|--quiet] [--cert <cert.der>] [-o|--output] <tainfo.der>\n");
|
---|
6230 | return RTEXITCODE_SUCCESS;
|
---|
6231 | }
|
---|
6232 |
|
---|
6233 |
|
---|
6234 | typedef struct MAKETAINFOSTATE
|
---|
6235 | {
|
---|
6236 | int cVerbose;
|
---|
6237 | const char *pszCert;
|
---|
6238 | const char *pszOutput;
|
---|
6239 | } MAKETAINFOSTATE;
|
---|
6240 |
|
---|
6241 |
|
---|
6242 | /** @callback_method_impl{FNRTASN1ENCODEWRITER} */
|
---|
6243 | static DECLCALLBACK(int) handleMakeTaInfoWriter(const void *pvBuf, size_t cbToWrite, void *pvUser, PRTERRINFO pErrInfo)
|
---|
6244 | {
|
---|
6245 | RT_NOREF_PV(pErrInfo);
|
---|
6246 | return RTStrmWrite((PRTSTREAM)pvUser, pvBuf, cbToWrite);
|
---|
6247 | }
|
---|
6248 |
|
---|
6249 |
|
---|
6250 | static RTEXITCODE HandleMakeTaInfo(int cArgs, char **papszArgs)
|
---|
6251 | {
|
---|
6252 | /*
|
---|
6253 | * Parse arguments.
|
---|
6254 | */
|
---|
6255 | static const RTGETOPTDEF s_aOptions[] =
|
---|
6256 | {
|
---|
6257 | { "--cert", 'c', RTGETOPT_REQ_STRING },
|
---|
6258 | { "--output", 'o', RTGETOPT_REQ_STRING },
|
---|
6259 | { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
|
---|
6260 | { "--quiet", 'q', RTGETOPT_REQ_NOTHING },
|
---|
6261 | };
|
---|
6262 |
|
---|
6263 | MAKETAINFOSTATE State = { 0, NULL, NULL };
|
---|
6264 |
|
---|
6265 | RTGETOPTSTATE GetState;
|
---|
6266 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
6267 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
6268 | RTGETOPTUNION ValueUnion;
|
---|
6269 | int ch;
|
---|
6270 | while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
|
---|
6271 | {
|
---|
6272 | switch (ch)
|
---|
6273 | {
|
---|
6274 | case 'c':
|
---|
6275 | if (State.pszCert)
|
---|
6276 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "The --cert option can only be used once.");
|
---|
6277 | State.pszCert = ValueUnion.psz;
|
---|
6278 | break;
|
---|
6279 |
|
---|
6280 | case 'o':
|
---|
6281 | case VINF_GETOPT_NOT_OPTION:
|
---|
6282 | if (State.pszOutput)
|
---|
6283 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Multiple output files specified.");
|
---|
6284 | State.pszOutput = ValueUnion.psz;
|
---|
6285 | break;
|
---|
6286 |
|
---|
6287 | case 'v': State.cVerbose++; break;
|
---|
6288 | case 'q': State.cVerbose = 0; break;
|
---|
6289 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
6290 | case 'h': return HelpMakeTaInfo(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
6291 | default: return RTGetOptPrintError(ch, &ValueUnion);
|
---|
6292 | }
|
---|
6293 | }
|
---|
6294 | if (!State.pszCert)
|
---|
6295 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No input certificate was specified.");
|
---|
6296 | if (!State.pszOutput)
|
---|
6297 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output file was specified.");
|
---|
6298 |
|
---|
6299 | /*
|
---|
6300 | * Read the certificate.
|
---|
6301 | */
|
---|
6302 | RTERRINFOSTATIC StaticErrInfo;
|
---|
6303 | RTCRX509CERTIFICATE Certificate;
|
---|
6304 | rc = RTCrX509Certificate_ReadFromFile(&Certificate, State.pszCert, 0, &g_RTAsn1DefaultAllocator,
|
---|
6305 | RTErrInfoInitStatic(&StaticErrInfo));
|
---|
6306 | if (RT_FAILURE(rc))
|
---|
6307 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error reading certificate from %s: %Rrc - %s",
|
---|
6308 | State.pszCert, rc, StaticErrInfo.szMsg);
|
---|
6309 | /*
|
---|
6310 | * Construct the trust anchor information.
|
---|
6311 | */
|
---|
6312 | RTCRTAFTRUSTANCHORINFO TrustAnchor;
|
---|
6313 | rc = RTCrTafTrustAnchorInfo_Init(&TrustAnchor, &g_RTAsn1DefaultAllocator);
|
---|
6314 | if (RT_SUCCESS(rc))
|
---|
6315 | {
|
---|
6316 | /* Public key. */
|
---|
6317 | Assert(RTCrX509SubjectPublicKeyInfo_IsPresent(&TrustAnchor.PubKey));
|
---|
6318 | RTCrX509SubjectPublicKeyInfo_Delete(&TrustAnchor.PubKey);
|
---|
6319 | rc = RTCrX509SubjectPublicKeyInfo_Clone(&TrustAnchor.PubKey, &Certificate.TbsCertificate.SubjectPublicKeyInfo,
|
---|
6320 | &g_RTAsn1DefaultAllocator);
|
---|
6321 | if (RT_FAILURE(rc))
|
---|
6322 | RTMsgError("RTCrX509SubjectPublicKeyInfo_Clone failed: %Rrc", rc);
|
---|
6323 | RTAsn1Core_ResetImplict(RTCrX509SubjectPublicKeyInfo_GetAsn1Core(&TrustAnchor.PubKey)); /* temporary hack. */
|
---|
6324 |
|
---|
6325 | /* Key Identifier. */
|
---|
6326 | PCRTASN1OCTETSTRING pKeyIdentifier = NULL;
|
---|
6327 | if (Certificate.TbsCertificate.T3.fFlags & RTCRX509TBSCERTIFICATE_F_PRESENT_SUBJECT_KEY_IDENTIFIER)
|
---|
6328 | pKeyIdentifier = Certificate.TbsCertificate.T3.pSubjectKeyIdentifier;
|
---|
6329 | else if ( (Certificate.TbsCertificate.T3.fFlags & RTCRX509TBSCERTIFICATE_F_PRESENT_AUTHORITY_KEY_IDENTIFIER)
|
---|
6330 | && RTCrX509Certificate_IsSelfSigned(&Certificate)
|
---|
6331 | && RTAsn1OctetString_IsPresent(&Certificate.TbsCertificate.T3.pAuthorityKeyIdentifier->KeyIdentifier) )
|
---|
6332 | pKeyIdentifier = &Certificate.TbsCertificate.T3.pAuthorityKeyIdentifier->KeyIdentifier;
|
---|
6333 | else if ( (Certificate.TbsCertificate.T3.fFlags & RTCRX509TBSCERTIFICATE_F_PRESENT_OLD_AUTHORITY_KEY_IDENTIFIER)
|
---|
6334 | && RTCrX509Certificate_IsSelfSigned(&Certificate)
|
---|
6335 | && RTAsn1OctetString_IsPresent(&Certificate.TbsCertificate.T3.pOldAuthorityKeyIdentifier->KeyIdentifier) )
|
---|
6336 | pKeyIdentifier = &Certificate.TbsCertificate.T3.pOldAuthorityKeyIdentifier->KeyIdentifier;
|
---|
6337 | if (pKeyIdentifier && pKeyIdentifier->Asn1Core.cb > 0)
|
---|
6338 | {
|
---|
6339 | Assert(RTAsn1OctetString_IsPresent(&TrustAnchor.KeyIdentifier));
|
---|
6340 | RTAsn1OctetString_Delete(&TrustAnchor.KeyIdentifier);
|
---|
6341 | rc = RTAsn1OctetString_Clone(&TrustAnchor.KeyIdentifier, pKeyIdentifier, &g_RTAsn1DefaultAllocator);
|
---|
6342 | if (RT_FAILURE(rc))
|
---|
6343 | RTMsgError("RTAsn1OctetString_Clone failed: %Rrc", rc);
|
---|
6344 | RTAsn1Core_ResetImplict(RTAsn1OctetString_GetAsn1Core(&TrustAnchor.KeyIdentifier)); /* temporary hack. */
|
---|
6345 | }
|
---|
6346 | else
|
---|
6347 | RTMsgWarning("No key identifier found or has zero length.");
|
---|
6348 |
|
---|
6349 | /* Subject */
|
---|
6350 | if (RT_SUCCESS(rc))
|
---|
6351 | {
|
---|
6352 | Assert(!RTCrTafCertPathControls_IsPresent(&TrustAnchor.CertPath));
|
---|
6353 | rc = RTCrTafCertPathControls_Init(&TrustAnchor.CertPath, &g_RTAsn1DefaultAllocator);
|
---|
6354 | if (RT_SUCCESS(rc))
|
---|
6355 | {
|
---|
6356 | Assert(RTCrX509Name_IsPresent(&TrustAnchor.CertPath.TaName));
|
---|
6357 | RTCrX509Name_Delete(&TrustAnchor.CertPath.TaName);
|
---|
6358 | rc = RTCrX509Name_Clone(&TrustAnchor.CertPath.TaName, &Certificate.TbsCertificate.Subject,
|
---|
6359 | &g_RTAsn1DefaultAllocator);
|
---|
6360 | if (RT_SUCCESS(rc))
|
---|
6361 | {
|
---|
6362 | RTAsn1Core_ResetImplict(RTCrX509Name_GetAsn1Core(&TrustAnchor.CertPath.TaName)); /* temporary hack. */
|
---|
6363 | rc = RTCrX509Name_RecodeAsUtf8(&TrustAnchor.CertPath.TaName, &g_RTAsn1DefaultAllocator);
|
---|
6364 | if (RT_FAILURE(rc))
|
---|
6365 | RTMsgError("RTCrX509Name_RecodeAsUtf8 failed: %Rrc", rc);
|
---|
6366 | }
|
---|
6367 | else
|
---|
6368 | RTMsgError("RTCrX509Name_Clone failed: %Rrc", rc);
|
---|
6369 | }
|
---|
6370 | else
|
---|
6371 | RTMsgError("RTCrTafCertPathControls_Init failed: %Rrc", rc);
|
---|
6372 | }
|
---|
6373 |
|
---|
6374 | /* Check that what we've constructed makes some sense. */
|
---|
6375 | if (RT_SUCCESS(rc))
|
---|
6376 | {
|
---|
6377 | rc = RTCrTafTrustAnchorInfo_CheckSanity(&TrustAnchor, 0, RTErrInfoInitStatic(&StaticErrInfo), "TAI");
|
---|
6378 | if (RT_FAILURE(rc))
|
---|
6379 | RTMsgError("RTCrTafTrustAnchorInfo_CheckSanity failed: %Rrc - %s", rc, StaticErrInfo.szMsg);
|
---|
6380 | }
|
---|
6381 |
|
---|
6382 | if (RT_SUCCESS(rc))
|
---|
6383 | {
|
---|
6384 | /*
|
---|
6385 | * Encode it and write it to the output file.
|
---|
6386 | */
|
---|
6387 | uint32_t cbEncoded;
|
---|
6388 | rc = RTAsn1EncodePrepare(RTCrTafTrustAnchorInfo_GetAsn1Core(&TrustAnchor), RTASN1ENCODE_F_DER, &cbEncoded,
|
---|
6389 | RTErrInfoInitStatic(&StaticErrInfo));
|
---|
6390 | if (RT_SUCCESS(rc))
|
---|
6391 | {
|
---|
6392 | if (State.cVerbose >= 1)
|
---|
6393 | RTAsn1Dump(RTCrTafTrustAnchorInfo_GetAsn1Core(&TrustAnchor), 0, 0, RTStrmDumpPrintfV, g_pStdOut);
|
---|
6394 |
|
---|
6395 | PRTSTREAM pStrm;
|
---|
6396 | rc = RTStrmOpen(State.pszOutput, "wb", &pStrm);
|
---|
6397 | if (RT_SUCCESS(rc))
|
---|
6398 | {
|
---|
6399 | rc = RTAsn1EncodeWrite(RTCrTafTrustAnchorInfo_GetAsn1Core(&TrustAnchor), RTASN1ENCODE_F_DER,
|
---|
6400 | handleMakeTaInfoWriter, pStrm, RTErrInfoInitStatic(&StaticErrInfo));
|
---|
6401 | if (RT_SUCCESS(rc))
|
---|
6402 | {
|
---|
6403 | rc = RTStrmClose(pStrm);
|
---|
6404 | if (RT_SUCCESS(rc))
|
---|
6405 | RTMsgInfo("Successfully wrote TrustedAnchorInfo to '%s'.", State.pszOutput);
|
---|
6406 | else
|
---|
6407 | RTMsgError("RTStrmClose failed: %Rrc", rc);
|
---|
6408 | }
|
---|
6409 | else
|
---|
6410 | {
|
---|
6411 | RTMsgError("RTAsn1EncodeWrite failed: %Rrc - %s", rc, StaticErrInfo.szMsg);
|
---|
6412 | RTStrmClose(pStrm);
|
---|
6413 | }
|
---|
6414 | }
|
---|
6415 | else
|
---|
6416 | RTMsgError("Error opening '%s' for writing: %Rrcs", State.pszOutput, rc);
|
---|
6417 | }
|
---|
6418 | else
|
---|
6419 | RTMsgError("RTAsn1EncodePrepare failed: %Rrc - %s", rc, StaticErrInfo.szMsg);
|
---|
6420 | }
|
---|
6421 |
|
---|
6422 | RTCrTafTrustAnchorInfo_Delete(&TrustAnchor);
|
---|
6423 | }
|
---|
6424 | else
|
---|
6425 | RTMsgError("RTCrTafTrustAnchorInfo_Init failed: %Rrc", rc);
|
---|
6426 |
|
---|
6427 | RTCrX509Certificate_Delete(&Certificate);
|
---|
6428 | return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
|
---|
6429 | }
|
---|
6430 |
|
---|
6431 |
|
---|
6432 |
|
---|
6433 | /*********************************************************************************************************************************
|
---|
6434 | * The 'create-self-signed-rsa-cert' command. *
|
---|
6435 | *********************************************************************************************************************************/
|
---|
6436 | #ifndef IPRT_IN_BUILD_TOOL
|
---|
6437 |
|
---|
6438 | static RTEXITCODE HelpCreateSelfSignedRsaCert(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
6439 | {
|
---|
6440 | RT_NOREF_PV(enmLevel);
|
---|
6441 | RTStrmWrappedPrintf(pStrm, RTSTRMWRAPPED_F_HANGING_INDENT,
|
---|
6442 | "create-self-signed-rsa-cert [--verbose|--quiet] [--key-bits <count>] [--digest <hash>] [--out-cert=]<certificate-file.pem> [--out-pkey=]<private-key-file.pem>\n");
|
---|
6443 | return RTEXITCODE_SUCCESS;
|
---|
6444 | }
|
---|
6445 |
|
---|
6446 |
|
---|
6447 | static RTDIGESTTYPE DigestTypeStringToValue(const char *pszType)
|
---|
6448 | {
|
---|
6449 | for (int iType = RTDIGESTTYPE_INVALID + 1; iType < RTDIGESTTYPE_END; iType++)
|
---|
6450 | if (iType != RTDIGESTTYPE_UNKNOWN)
|
---|
6451 | {
|
---|
6452 | const char * const pszName = RTCrDigestTypeToName((RTDIGESTTYPE)iType);
|
---|
6453 | size_t offType = 0;
|
---|
6454 | size_t offName = 0;
|
---|
6455 | for (;;)
|
---|
6456 | {
|
---|
6457 | char chType = RT_C_TO_UPPER(pszType[offType]);
|
---|
6458 | char chName = RT_C_TO_UPPER(pszName[offType]);
|
---|
6459 | if (chType != chName)
|
---|
6460 | {
|
---|
6461 | /* allow 'sha1' as well as 'sha-1' */
|
---|
6462 | if (chName != '-')
|
---|
6463 | break;
|
---|
6464 | chName = pszName[++offName];
|
---|
6465 | chName = RT_C_TO_UPPER(chName);
|
---|
6466 | if (chType != chName)
|
---|
6467 | break;
|
---|
6468 | }
|
---|
6469 | if (chType == '\0')
|
---|
6470 | return (RTDIGESTTYPE)iType;
|
---|
6471 | }
|
---|
6472 | }
|
---|
6473 | return RTDIGESTTYPE_INVALID;
|
---|
6474 | }
|
---|
6475 |
|
---|
6476 |
|
---|
6477 | static RTEXITCODE HandleCreateSelfSignedRsaCert(int cArgs, char **papszArgs)
|
---|
6478 | {
|
---|
6479 | /*
|
---|
6480 | * Parse arguments.
|
---|
6481 | */
|
---|
6482 | static const RTGETOPTDEF s_aOptions[] =
|
---|
6483 | {
|
---|
6484 | { "--digest", 'd', RTGETOPT_REQ_STRING },
|
---|
6485 | { "--bits", 'b', RTGETOPT_REQ_UINT32 },
|
---|
6486 | { "--key-bits", 'b', RTGETOPT_REQ_UINT32 },
|
---|
6487 | { "--days", 'D', RTGETOPT_REQ_UINT32 },
|
---|
6488 | { "--days", 'D', RTGETOPT_REQ_UINT32 },
|
---|
6489 | { "--out-cert", 'c', RTGETOPT_REQ_UINT32 },
|
---|
6490 | { "--out-certificate", 'c', RTGETOPT_REQ_UINT32 },
|
---|
6491 | { "--out-pkey", 'p', RTGETOPT_REQ_UINT32 },
|
---|
6492 | { "--out-private-key", 'p', RTGETOPT_REQ_UINT32 },
|
---|
6493 | { "--secs", 's', RTGETOPT_REQ_UINT32 },
|
---|
6494 | { "--seconds", 's', RTGETOPT_REQ_UINT32 },
|
---|
6495 | };
|
---|
6496 |
|
---|
6497 | RTDIGESTTYPE enmDigestType = RTDIGESTTYPE_SHA384;
|
---|
6498 | uint32_t cKeyBits = 4096;
|
---|
6499 | uint32_t cSecsValidFor = 365 * RT_SEC_1DAY;
|
---|
6500 | uint32_t fKeyUsage = 0;
|
---|
6501 | uint32_t fExtKeyUsage = 0;
|
---|
6502 | const char *pszOutCert = NULL;
|
---|
6503 | const char *pszOutPrivKey = NULL;
|
---|
6504 |
|
---|
6505 | RTGETOPTSTATE GetState;
|
---|
6506 | int rc = RTGetOptInit(&GetState, cArgs, papszArgs, s_aOptions, RT_ELEMENTS(s_aOptions), 1, RTGETOPTINIT_FLAGS_OPTS_FIRST);
|
---|
6507 | AssertRCReturn(rc, RTEXITCODE_FAILURE);
|
---|
6508 | RTGETOPTUNION ValueUnion;
|
---|
6509 | int ch;
|
---|
6510 | while ((ch = RTGetOpt(&GetState, &ValueUnion)) != 0)
|
---|
6511 | {
|
---|
6512 | switch (ch)
|
---|
6513 | {
|
---|
6514 | case 'b':
|
---|
6515 | cKeyBits = ValueUnion.u32;
|
---|
6516 | break;
|
---|
6517 |
|
---|
6518 | case 'd':
|
---|
6519 | enmDigestType = DigestTypeStringToValue(ValueUnion.psz);
|
---|
6520 | if (enmDigestType == RTDIGESTTYPE_INVALID)
|
---|
6521 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Unknown digest type: %s", ValueUnion.psz);
|
---|
6522 | break;
|
---|
6523 |
|
---|
6524 | case 'D':
|
---|
6525 | cSecsValidFor = ValueUnion.u32 * RT_SEC_1DAY;
|
---|
6526 | if (cSecsValidFor / RT_SEC_1DAY != ValueUnion.u32)
|
---|
6527 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "The --days option value is out of range: %u", ValueUnion.u32);
|
---|
6528 | break;
|
---|
6529 |
|
---|
6530 | case 'c':
|
---|
6531 | if (pszOutCert)
|
---|
6532 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "The --out-cert option can only be used once.");
|
---|
6533 | pszOutCert = ValueUnion.psz;
|
---|
6534 | break;
|
---|
6535 |
|
---|
6536 | case 'p':
|
---|
6537 | if (pszOutPrivKey)
|
---|
6538 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "The --out-pkey option can only be used once.");
|
---|
6539 | pszOutPrivKey = ValueUnion.psz;
|
---|
6540 | break;
|
---|
6541 |
|
---|
6542 | case 's':
|
---|
6543 | cSecsValidFor = ValueUnion.u32;
|
---|
6544 | break;
|
---|
6545 |
|
---|
6546 | case VINF_GETOPT_NOT_OPTION:
|
---|
6547 | if (!pszOutCert)
|
---|
6548 | pszOutCert = ValueUnion.psz;
|
---|
6549 | else if (!pszOutPrivKey)
|
---|
6550 | pszOutPrivKey = ValueUnion.psz;
|
---|
6551 | else
|
---|
6552 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Too many output files specified: %s", ValueUnion.psz);
|
---|
6553 | break;
|
---|
6554 |
|
---|
6555 | case 'V': return HandleVersion(cArgs, papszArgs);
|
---|
6556 | case 'h': return HelpCreateSelfSignedRsaCert(g_pStdOut, RTSIGNTOOLHELP_FULL);
|
---|
6557 | default: return RTGetOptPrintError(ch, &ValueUnion);
|
---|
6558 | }
|
---|
6559 | }
|
---|
6560 | if (!pszOutCert)
|
---|
6561 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output certificate file name specified.");
|
---|
6562 | if (!pszOutPrivKey)
|
---|
6563 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "No output private key file name specified.");
|
---|
6564 |
|
---|
6565 | /*
|
---|
6566 | * Do the work.
|
---|
6567 | */
|
---|
6568 | RTERRINFOSTATIC StaticErrInfo;
|
---|
6569 | rc = RTCrX509Certificate_GenerateSelfSignedRsa(enmDigestType, cKeyBits, cSecsValidFor,
|
---|
6570 | fKeyUsage, fExtKeyUsage, NULL /*pvSubjectTodo*/,
|
---|
6571 | pszOutCert, pszOutPrivKey, RTErrInfoInitStatic(&StaticErrInfo));
|
---|
6572 | if (RT_SUCCESS(rc))
|
---|
6573 | {
|
---|
6574 | /*
|
---|
6575 | * Test load it.
|
---|
6576 | */
|
---|
6577 | RTCRX509CERTIFICATE Certificate;
|
---|
6578 | rc = RTCrX509Certificate_ReadFromFile(&Certificate, pszOutCert, RTCRX509CERT_READ_F_PEM_ONLY,
|
---|
6579 | &g_RTAsn1DefaultAllocator, RTErrInfoInitStatic(&StaticErrInfo));
|
---|
6580 | if (RT_FAILURE(rc))
|
---|
6581 | return RTMsgErrorExit(RTEXITCODE_FAILURE, "Error reading the new certificate from %s: %Rrc%#RTeim",
|
---|
6582 | pszOutCert, rc, &StaticErrInfo.Core);
|
---|
6583 | RTCrX509Certificate_Delete(&Certificate);
|
---|
6584 | return RTEXITCODE_SUCCESS;
|
---|
6585 | }
|
---|
6586 |
|
---|
6587 | return RTMsgErrorExitFailure("RTCrX509Certificate_GenerateSelfSignedRsa(%d,%u,%u,%s,%s,) failed: %Rrc%#RTeim",
|
---|
6588 | enmDigestType, cKeyBits, cSecsValidFor, pszOutCert, pszOutPrivKey, rc, &StaticErrInfo.Core);
|
---|
6589 | }
|
---|
6590 |
|
---|
6591 | #endif /* !IPRT_IN_BUILD_TOOL */
|
---|
6592 |
|
---|
6593 |
|
---|
6594 | /*
|
---|
6595 | * The 'version' command.
|
---|
6596 | */
|
---|
6597 | static RTEXITCODE HelpVersion(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
6598 | {
|
---|
6599 | RT_NOREF_PV(enmLevel);
|
---|
6600 | RTStrmPrintf(pStrm, "version\n");
|
---|
6601 | return RTEXITCODE_SUCCESS;
|
---|
6602 | }
|
---|
6603 |
|
---|
6604 | static RTEXITCODE HandleVersion(int cArgs, char **papszArgs)
|
---|
6605 | {
|
---|
6606 | RT_NOREF_PV(cArgs); RT_NOREF_PV(papszArgs);
|
---|
6607 | #ifndef IN_BLD_PROG /* RTBldCfgVersion or RTBldCfgRevision in build time IPRT lib. */
|
---|
6608 | RTPrintf("%s\n", RTBldCfgVersion());
|
---|
6609 | return RTEXITCODE_SUCCESS;
|
---|
6610 | #else
|
---|
6611 | return RTEXITCODE_FAILURE;
|
---|
6612 | #endif
|
---|
6613 | }
|
---|
6614 |
|
---|
6615 |
|
---|
6616 |
|
---|
6617 | /**
|
---|
6618 | * Command mapping.
|
---|
6619 | */
|
---|
6620 | static struct
|
---|
6621 | {
|
---|
6622 | /** The command. */
|
---|
6623 | const char *pszCmd;
|
---|
6624 | /**
|
---|
6625 | * Handle the command.
|
---|
6626 | * @returns Program exit code.
|
---|
6627 | * @param cArgs Number of arguments.
|
---|
6628 | * @param papszArgs The argument vector, starting with the command name.
|
---|
6629 | */
|
---|
6630 | RTEXITCODE (*pfnHandler)(int cArgs, char **papszArgs);
|
---|
6631 | /**
|
---|
6632 | * Produce help.
|
---|
6633 | * @returns RTEXITCODE_SUCCESS to simplify handling '--help' in the handler.
|
---|
6634 | * @param pStrm Where to send help text.
|
---|
6635 | * @param enmLevel The level of the help information.
|
---|
6636 | */
|
---|
6637 | RTEXITCODE (*pfnHelp)(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel);
|
---|
6638 | }
|
---|
6639 | /** Mapping commands to handler and helper functions. */
|
---|
6640 | const g_aCommands[] =
|
---|
6641 | {
|
---|
6642 | { "extract-exe-signer-cert", HandleExtractExeSignerCert, HelpExtractExeSignerCert },
|
---|
6643 | { "extract-signer-root", HandleExtractSignerRoot, HelpExtractSignerRoot },
|
---|
6644 | { "extract-timestamp-root", HandleExtractTimestampRoot, HelpExtractTimestampRoot },
|
---|
6645 | { "extract-exe-signature", HandleExtractExeSignature, HelpExtractExeSignature },
|
---|
6646 | { "add-nested-exe-signature", HandleAddNestedExeSignature, HelpAddNestedExeSignature },
|
---|
6647 | { "add-nested-cat-signature", HandleAddNestedCatSignature, HelpAddNestedCatSignature },
|
---|
6648 | #ifndef IPRT_SIGNTOOL_NO_SIGNING
|
---|
6649 | { "add-timestamp-exe-signature", HandleAddTimestampExeSignature, HelpAddTimestampExeSignature },
|
---|
6650 | { "sign", HandleSign, HelpSign },
|
---|
6651 | #endif
|
---|
6652 | #ifndef IPRT_IN_BUILD_TOOL
|
---|
6653 | { "verify-exe", HandleVerifyExe, HelpVerifyExe },
|
---|
6654 | #endif
|
---|
6655 | { "show-exe", HandleShowExe, HelpShowExe },
|
---|
6656 | { "show-cat", HandleShowCat, HelpShowCat },
|
---|
6657 | { "hash-exe", HandleHashExe, HelpHashExe },
|
---|
6658 | { "make-tainfo", HandleMakeTaInfo, HelpMakeTaInfo },
|
---|
6659 | #ifndef IPRT_IN_BUILD_TOOL
|
---|
6660 | { "create-self-signed-rsa-cert", HandleCreateSelfSignedRsaCert, HelpCreateSelfSignedRsaCert },
|
---|
6661 | #endif
|
---|
6662 | { "help", HandleHelp, HelpHelp },
|
---|
6663 | { "--help", HandleHelp, NULL },
|
---|
6664 | { "-h", HandleHelp, NULL },
|
---|
6665 | { "version", HandleVersion, HelpVersion },
|
---|
6666 | { "--version", HandleVersion, NULL },
|
---|
6667 | { "-V", HandleVersion, NULL },
|
---|
6668 | };
|
---|
6669 |
|
---|
6670 |
|
---|
6671 | /*
|
---|
6672 | * The 'help' command.
|
---|
6673 | */
|
---|
6674 | static RTEXITCODE HelpHelp(PRTSTREAM pStrm, RTSIGNTOOLHELP enmLevel)
|
---|
6675 | {
|
---|
6676 | RT_NOREF_PV(enmLevel);
|
---|
6677 | RTStrmPrintf(pStrm, "help [cmd-patterns]\n");
|
---|
6678 | return RTEXITCODE_SUCCESS;
|
---|
6679 | }
|
---|
6680 |
|
---|
6681 | static RTEXITCODE HandleHelp(int cArgs, char **papszArgs)
|
---|
6682 | {
|
---|
6683 | PRTSTREAM const pStrm = g_pStdOut;
|
---|
6684 | RTSIGNTOOLHELP enmLevel = cArgs <= 1 ? RTSIGNTOOLHELP_USAGE : RTSIGNTOOLHELP_FULL;
|
---|
6685 | uint32_t cShowed = 0;
|
---|
6686 | uint32_t cchWidth;
|
---|
6687 | if (RT_FAILURE(RTStrmQueryTerminalWidth(g_pStdOut, &cchWidth)))
|
---|
6688 | cchWidth = 80;
|
---|
6689 |
|
---|
6690 | RTStrmPrintf(pStrm,
|
---|
6691 | "Usage: RTSignTool <command> [command-options]\n"
|
---|
6692 | " or: RTSignTool <-V|--version|version>\n"
|
---|
6693 | " or: RTSignTool <-h|--help|help> [command-pattern [..]]\n"
|
---|
6694 | "\n"
|
---|
6695 | );
|
---|
6696 |
|
---|
6697 | if (enmLevel == RTSIGNTOOLHELP_USAGE)
|
---|
6698 | RTStrmPrintf(pStrm, "Syntax summary for the RTSignTool commands:\n");
|
---|
6699 |
|
---|
6700 | for (uint32_t iCmd = 0; iCmd < RT_ELEMENTS(g_aCommands); iCmd++)
|
---|
6701 | {
|
---|
6702 | if (g_aCommands[iCmd].pfnHelp)
|
---|
6703 | {
|
---|
6704 | bool fShow = false;
|
---|
6705 | if (cArgs <= 1)
|
---|
6706 | fShow = true;
|
---|
6707 | else
|
---|
6708 | for (int iArg = 1; iArg < cArgs; iArg++)
|
---|
6709 | if (RTStrSimplePatternMultiMatch(papszArgs[iArg], RTSTR_MAX, g_aCommands[iCmd].pszCmd, RTSTR_MAX, NULL))
|
---|
6710 | {
|
---|
6711 | fShow = true;
|
---|
6712 | break;
|
---|
6713 | }
|
---|
6714 | if (fShow)
|
---|
6715 | {
|
---|
6716 | if (enmLevel == RTSIGNTOOLHELP_FULL)
|
---|
6717 | RTPrintf("%.*s\n", RT_MIN(cchWidth, 100),
|
---|
6718 | "- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ");
|
---|
6719 | g_aCommands[iCmd].pfnHelp(pStrm, enmLevel);
|
---|
6720 | cShowed++;
|
---|
6721 | }
|
---|
6722 | }
|
---|
6723 | }
|
---|
6724 | return cShowed ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE;
|
---|
6725 | }
|
---|
6726 |
|
---|
6727 |
|
---|
6728 |
|
---|
6729 | int main(int argc, char **argv)
|
---|
6730 | {
|
---|
6731 | int rc = RTR3InitExe(argc, &argv, 0);
|
---|
6732 | if (RT_FAILURE(rc))
|
---|
6733 | return RTMsgInitFailure(rc);
|
---|
6734 |
|
---|
6735 | /*
|
---|
6736 | * Parse global arguments.
|
---|
6737 | */
|
---|
6738 | int iArg = 1;
|
---|
6739 | /* none presently. */
|
---|
6740 |
|
---|
6741 | /*
|
---|
6742 | * Command dispatcher.
|
---|
6743 | */
|
---|
6744 | if (iArg < argc)
|
---|
6745 | {
|
---|
6746 | const char *pszCmd = argv[iArg];
|
---|
6747 | uint32_t i = RT_ELEMENTS(g_aCommands);
|
---|
6748 | while (i-- > 0)
|
---|
6749 | if (!strcmp(g_aCommands[i].pszCmd, pszCmd))
|
---|
6750 | return g_aCommands[i].pfnHandler(argc - iArg, &argv[iArg]);
|
---|
6751 | RTMsgError("Unknown command '%s'.", pszCmd);
|
---|
6752 | }
|
---|
6753 | else
|
---|
6754 | RTMsgError("No command given. (try --help)");
|
---|
6755 |
|
---|
6756 | return RTEXITCODE_SYNTAX;
|
---|
6757 | }
|
---|
6758 |
|
---|