Skip to content

Commit e5a2e3c

Browse files
Juerg Haefligerdhowells
authored andcommitted
scripts/sign-file.c: Add support for signing with a raw signature
This patch adds support for signing a kernel module with a raw detached PKCS#7 signature/message. The signature is not converted and is simply appended to the module so it needs to be in the right format. Using openssl, a valid signature can be generated like this: $ openssl smime -sign -nocerts -noattr -binary -in <module> -inkey \ <key> -signer <x509> -outform der -out <raw sig> The resulting raw signature from the above command is (more or less) identical to the raw signature that sign-file itself can produce like this: $ scripts/sign-file -d <hash algo> <key> <x509> <module> Signed-off-by: Juerg Haefliger <[email protected]> Signed-off-by: David Howells <[email protected]>
1 parent a1f2bdf commit e5a2e3c

File tree

1 file changed

+146
-90
lines changed

1 file changed

+146
-90
lines changed

scripts/sign-file.c

Lines changed: 146 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,11 @@
22
*
33
* Copyright © 2014-2015 Red Hat, Inc. All Rights Reserved.
44
* Copyright © 2015 Intel Corporation.
5+
* Copyright © 2016 Hewlett Packard Enterprise Development LP
56
*
67
* Authors: David Howells <[email protected]>
78
* David Woodhouse <[email protected]>
9+
* Juerg Haefliger <[email protected]>
810
*
911
* This program is free software; you can redistribute it and/or
1012
* modify it under the terms of the GNU Lesser General Public License
@@ -67,6 +69,8 @@ void format(void)
6769
{
6870
fprintf(stderr,
6971
"Usage: scripts/sign-file [-dp] <hash algo> <key> <x509> <module> [<dest>]\n");
72+
fprintf(stderr,
73+
" scripts/sign-file -s <raw sig> <hash algo> <x509> <module> [<dest>]\n");
7074
exit(2);
7175
}
7276

@@ -126,26 +130,84 @@ static int pem_pw_cb(char *buf, int len, int w, void *v)
126130
return pwlen;
127131
}
128132

133+
static EVP_PKEY *read_private_key(const char *private_key_name)
134+
{
135+
EVP_PKEY *private_key;
136+
137+
if (!strncmp(private_key_name, "pkcs11:", 7)) {
138+
ENGINE *e;
139+
140+
ENGINE_load_builtin_engines();
141+
drain_openssl_errors();
142+
e = ENGINE_by_id("pkcs11");
143+
ERR(!e, "Load PKCS#11 ENGINE");
144+
if (ENGINE_init(e))
145+
drain_openssl_errors();
146+
else
147+
ERR(1, "ENGINE_init");
148+
if (key_pass)
149+
ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0),
150+
"Set PKCS#11 PIN");
151+
private_key = ENGINE_load_private_key(e, private_key_name,
152+
NULL, NULL);
153+
ERR(!private_key, "%s", private_key_name);
154+
} else {
155+
BIO *b;
156+
157+
b = BIO_new_file(private_key_name, "rb");
158+
ERR(!b, "%s", private_key_name);
159+
private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb,
160+
NULL);
161+
ERR(!private_key, "%s", private_key_name);
162+
BIO_free(b);
163+
}
164+
165+
return private_key;
166+
}
167+
168+
static X509 *read_x509(const char *x509_name)
169+
{
170+
X509 *x509;
171+
BIO *b;
172+
173+
b = BIO_new_file(x509_name, "rb");
174+
ERR(!b, "%s", x509_name);
175+
x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */
176+
if (!x509) {
177+
ERR(BIO_reset(b) != 1, "%s", x509_name);
178+
x509 = PEM_read_bio_X509(b, NULL, NULL,
179+
NULL); /* PEM encoded X.509 */
180+
if (x509)
181+
drain_openssl_errors();
182+
}
183+
BIO_free(b);
184+
ERR(!x509, "%s", x509_name);
185+
186+
return x509;
187+
}
188+
129189
int main(int argc, char **argv)
130190
{
131191
struct module_signature sig_info = { .id_type = PKEY_ID_PKCS7 };
132192
char *hash_algo = NULL;
133-
char *private_key_name, *x509_name, *module_name, *dest_name;
193+
char *private_key_name = NULL, *raw_sig_name = NULL;
194+
char *x509_name, *module_name, *dest_name;
134195
bool save_sig = false, replace_orig;
135196
bool sign_only = false;
197+
bool raw_sig = false;
136198
unsigned char buf[4096];
137199
unsigned long module_size, sig_size;
138200
unsigned int use_signed_attrs;
139201
const EVP_MD *digest_algo;
140202
EVP_PKEY *private_key;
141203
#ifndef USE_PKCS7
142-
CMS_ContentInfo *cms;
204+
CMS_ContentInfo *cms = NULL;
143205
unsigned int use_keyid = 0;
144206
#else
145-
PKCS7 *pkcs7;
207+
PKCS7 *pkcs7 = NULL;
146208
#endif
147209
X509 *x509;
148-
BIO *b, *bd = NULL, *bm;
210+
BIO *bd, *bm;
149211
int opt, n;
150212
OpenSSL_add_all_algorithms();
151213
ERR_load_crypto_strings();
@@ -160,8 +222,9 @@ int main(int argc, char **argv)
160222
#endif
161223

162224
do {
163-
opt = getopt(argc, argv, "dpk");
225+
opt = getopt(argc, argv, "sdpk");
164226
switch (opt) {
227+
case 's': raw_sig = true; break;
165228
case 'p': save_sig = true; break;
166229
case 'd': sign_only = true; save_sig = true; break;
167230
#ifndef USE_PKCS7
@@ -177,8 +240,13 @@ int main(int argc, char **argv)
177240
if (argc < 4 || argc > 5)
178241
format();
179242

180-
hash_algo = argv[0];
181-
private_key_name = argv[1];
243+
if (raw_sig) {
244+
raw_sig_name = argv[0];
245+
hash_algo = argv[1];
246+
} else {
247+
hash_algo = argv[0];
248+
private_key_name = argv[1];
249+
}
182250
x509_name = argv[2];
183251
module_name = argv[3];
184252
if (argc == 5) {
@@ -198,116 +266,104 @@ int main(int argc, char **argv)
198266
}
199267
#endif
200268

201-
/* Read the private key and the X.509 cert the PKCS#7 message
202-
* will point to.
203-
*/
204-
if (!strncmp(private_key_name, "pkcs11:", 7)) {
205-
ENGINE *e;
206-
207-
ENGINE_load_builtin_engines();
208-
drain_openssl_errors();
209-
e = ENGINE_by_id("pkcs11");
210-
ERR(!e, "Load PKCS#11 ENGINE");
211-
if (ENGINE_init(e))
212-
drain_openssl_errors();
213-
else
214-
ERR(1, "ENGINE_init");
215-
if (key_pass)
216-
ERR(!ENGINE_ctrl_cmd_string(e, "PIN", key_pass, 0), "Set PKCS#11 PIN");
217-
private_key = ENGINE_load_private_key(e, private_key_name, NULL,
218-
NULL);
219-
ERR(!private_key, "%s", private_key_name);
220-
} else {
221-
b = BIO_new_file(private_key_name, "rb");
222-
ERR(!b, "%s", private_key_name);
223-
private_key = PEM_read_bio_PrivateKey(b, NULL, pem_pw_cb, NULL);
224-
ERR(!private_key, "%s", private_key_name);
225-
BIO_free(b);
226-
}
227-
228-
b = BIO_new_file(x509_name, "rb");
229-
ERR(!b, "%s", x509_name);
230-
x509 = d2i_X509_bio(b, NULL); /* Binary encoded X.509 */
231-
if (!x509) {
232-
ERR(BIO_reset(b) != 1, "%s", x509_name);
233-
x509 = PEM_read_bio_X509(b, NULL, NULL, NULL); /* PEM encoded X.509 */
234-
if (x509)
235-
drain_openssl_errors();
236-
}
237-
BIO_free(b);
238-
ERR(!x509, "%s", x509_name);
239-
240-
/* Open the destination file now so that we can shovel the module data
241-
* across as we read it.
242-
*/
243-
if (!sign_only) {
244-
bd = BIO_new_file(dest_name, "wb");
245-
ERR(!bd, "%s", dest_name);
246-
}
247-
248-
/* Digest the module data. */
249-
OpenSSL_add_all_digests();
250-
display_openssl_errors(__LINE__);
251-
digest_algo = EVP_get_digestbyname(hash_algo);
252-
ERR(!digest_algo, "EVP_get_digestbyname");
253-
269+
/* Open the module file */
254270
bm = BIO_new_file(module_name, "rb");
255271
ERR(!bm, "%s", module_name);
256272

273+
if (!raw_sig) {
274+
/* Read the private key and the X.509 cert the PKCS#7 message
275+
* will point to.
276+
*/
277+
private_key = read_private_key(private_key_name);
278+
x509 = read_x509(x509_name);
279+
280+
/* Digest the module data. */
281+
OpenSSL_add_all_digests();
282+
display_openssl_errors(__LINE__);
283+
digest_algo = EVP_get_digestbyname(hash_algo);
284+
ERR(!digest_algo, "EVP_get_digestbyname");
285+
257286
#ifndef USE_PKCS7
258-
/* Load the signature message from the digest buffer. */
259-
cms = CMS_sign(NULL, NULL, NULL, NULL,
260-
CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY | CMS_DETACHED | CMS_STREAM);
261-
ERR(!cms, "CMS_sign");
262-
263-
ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
264-
CMS_NOCERTS | CMS_BINARY | CMS_NOSMIMECAP |
265-
use_keyid | use_signed_attrs),
266-
"CMS_add1_signer");
267-
ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
268-
"CMS_final");
287+
/* Load the signature message from the digest buffer. */
288+
cms = CMS_sign(NULL, NULL, NULL, NULL,
289+
CMS_NOCERTS | CMS_PARTIAL | CMS_BINARY |
290+
CMS_DETACHED | CMS_STREAM);
291+
ERR(!cms, "CMS_sign");
292+
293+
ERR(!CMS_add1_signer(cms, x509, private_key, digest_algo,
294+
CMS_NOCERTS | CMS_BINARY |
295+
CMS_NOSMIMECAP | use_keyid |
296+
use_signed_attrs),
297+
"CMS_add1_signer");
298+
ERR(CMS_final(cms, bm, NULL, CMS_NOCERTS | CMS_BINARY) < 0,
299+
"CMS_final");
269300

270301
#else
271-
pkcs7 = PKCS7_sign(x509, private_key, NULL, bm,
272-
PKCS7_NOCERTS | PKCS7_BINARY |
273-
PKCS7_DETACHED | use_signed_attrs);
274-
ERR(!pkcs7, "PKCS7_sign");
302+
pkcs7 = PKCS7_sign(x509, private_key, NULL, bm,
303+
PKCS7_NOCERTS | PKCS7_BINARY |
304+
PKCS7_DETACHED | use_signed_attrs);
305+
ERR(!pkcs7, "PKCS7_sign");
275306
#endif
276307

277-
if (save_sig) {
278-
char *sig_file_name;
308+
if (save_sig) {
309+
char *sig_file_name;
310+
BIO *b;
279311

280-
ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0,
281-
"asprintf");
282-
b = BIO_new_file(sig_file_name, "wb");
283-
ERR(!b, "%s", sig_file_name);
312+
ERR(asprintf(&sig_file_name, "%s.p7s", module_name) < 0,
313+
"asprintf");
314+
b = BIO_new_file(sig_file_name, "wb");
315+
ERR(!b, "%s", sig_file_name);
284316
#ifndef USE_PKCS7
285-
ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0,
286-
"%s", sig_file_name);
317+
ERR(i2d_CMS_bio_stream(b, cms, NULL, 0) < 0,
318+
"%s", sig_file_name);
287319
#else
288-
ERR(i2d_PKCS7_bio(b, pkcs7) < 0,
289-
"%s", sig_file_name);
320+
ERR(i2d_PKCS7_bio(b, pkcs7) < 0,
321+
"%s", sig_file_name);
290322
#endif
291-
BIO_free(b);
323+
BIO_free(b);
324+
}
325+
326+
if (sign_only) {
327+
BIO_free(bm);
328+
return 0;
329+
}
292330
}
293331

294-
if (sign_only)
295-
return 0;
332+
/* Open the destination file now so that we can shovel the module data
333+
* across as we read it.
334+
*/
335+
bd = BIO_new_file(dest_name, "wb");
336+
ERR(!bd, "%s", dest_name);
296337

297338
/* Append the marker and the PKCS#7 message to the destination file */
298339
ERR(BIO_reset(bm) < 0, "%s", module_name);
299340
while ((n = BIO_read(bm, buf, sizeof(buf))),
300341
n > 0) {
301342
ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
302343
}
344+
BIO_free(bm);
303345
ERR(n < 0, "%s", module_name);
304346
module_size = BIO_number_written(bd);
305347

348+
if (!raw_sig) {
306349
#ifndef USE_PKCS7
307-
ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name);
350+
ERR(i2d_CMS_bio_stream(bd, cms, NULL, 0) < 0, "%s", dest_name);
308351
#else
309-
ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name);
352+
ERR(i2d_PKCS7_bio(bd, pkcs7) < 0, "%s", dest_name);
310353
#endif
354+
} else {
355+
BIO *b;
356+
357+
/* Read the raw signature file and write the data to the
358+
* destination file
359+
*/
360+
b = BIO_new_file(raw_sig_name, "rb");
361+
ERR(!b, "%s", raw_sig_name);
362+
while ((n = BIO_read(b, buf, sizeof(buf))), n > 0)
363+
ERR(BIO_write(bd, buf, n) < 0, "%s", dest_name);
364+
BIO_free(b);
365+
}
366+
311367
sig_size = BIO_number_written(bd) - module_size;
312368
sig_info.sig_len = htonl(sig_size);
313369
ERR(BIO_write(bd, &sig_info, sizeof(sig_info)) < 0, "%s", dest_name);

0 commit comments

Comments
 (0)