File: openssl_sign.c

package info (click to toggle)
efitools 1.9.2-3.6
  • links: PTS, VCS
  • area: main
  • in suites: forky
  • size: 948 kB
  • sloc: ansic: 7,550; makefile: 131; perl: 119; sh: 35
file content (156 lines) | stat: -rw-r--r-- 3,683 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
 * Copyright 2019 <James.Bottomley@HansenPartnership.com>
 *
 * see COPYING file
 */

#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/sha.h>
#include <openssl/engine.h>

#include <openssl_sign.h>

int
sign_efi_var_ssl(char *payload, int payload_size, EVP_PKEY *pkey, X509 *cert,
		 unsigned char **sig, int *sigsize)
{
	BIO *bio_data = BIO_new_mem_buf(payload, payload_size);
	PKCS7 *p7;

	p7 = PKCS7_sign(NULL, NULL, NULL, bio_data, PKCS7_BINARY|PKCS7_PARTIAL|PKCS7_DETACHED|PKCS7_NOATTR);
	const EVP_MD *md = EVP_get_digestbyname("SHA256");
	PKCS7_sign_add_signer(p7, cert, pkey, md, PKCS7_BINARY|PKCS7_DETACHED|PKCS7_NOATTR);
	PKCS7_final(p7, bio_data, PKCS7_BINARY|PKCS7_DETACHED|PKCS7_NOATTR);

	*sig = NULL;
	*sigsize = i2d_PKCS7_SIGNED(p7->d.sign, sig);
	PKCS7_free(p7);
	ERR_print_errors_fp(stdout);

	return 0;
}

int
sign_efi_var(char *payload, int payload_size, char *keyfile, char *certfile,
	     unsigned char **sig, int *sigsize, char *engine)
{
	int ret;

	ERR_load_crypto_strings();
	OpenSSL_add_all_digests();
	OpenSSL_add_all_ciphers();
	/* here we may get highly unlikely failures or we'll get a
	 * complaint about FIPS signatures (usually becuase the FIPS
	 * module isn't present).  In either case ignore the errors
	 * (malloc will cause other failures out lower down */
	ERR_clear_error();

	BIO *cert_bio = BIO_new_file(certfile, "r");
	if (!cert_bio) {
		ERR_print_errors_fp(stdout);
		fprintf(stderr, "error reading certificate %s\n", certfile);
		return 1;
	}
	X509 *cert = PEM_read_bio_X509(cert_bio, NULL, NULL, NULL);
	BIO_free(cert_bio);
	if (!cert) {
		ERR_print_errors_fp(stdout);
		fprintf(stderr, "error reading certificate %s\n", certfile);
		return 1;
	}

	EVP_PKEY *pkey = read_private_key(engine, keyfile);
	if (!pkey) {
		ERR_print_errors_fp(stdout);
		fprintf(stderr, "error reading private key %s\n", keyfile);
		return 1;
	}
	ret = sign_efi_var_ssl(payload, payload_size, pkey, cert,
			       sig, sigsize);
	EVP_PKEY_free(pkey);
	X509_free(cert);

	return ret;
}

static EVP_PKEY *
read_pem_private_key(char *keyfile)
{
	BIO *key = BIO_new_file(keyfile, "r");
	EVP_PKEY *pkey;

	if (!key) {
		ERR_print_errors_fp(stdout);
		fprintf(stderr, "error reading private key file %s\n", keyfile);
		return NULL;
	}
	pkey = PEM_read_bio_PrivateKey(key, NULL, NULL, NULL);
	BIO_free(key);

	if (!pkey) {
		ERR_print_errors_fp(stdout);
		fprintf(stderr, "error processing private key file %s\n", keyfile);
		return NULL;
	}
	return pkey;
}

static int ui_read(UI *ui, UI_STRING *uis)
{
	char password[128];

	if (UI_get_string_type(uis) != UIT_PROMPT)
		return 0;

	EVP_read_pw_string(password, sizeof(password), "Enter engine key pass phrase:", 0);
	UI_set_result(ui, uis, password);
	return 1;
}

static EVP_PKEY *
read_engine_private_key(char *engine, char *keyfile)
{
	UI_METHOD *ui;
	ENGINE *e;
	EVP_PKEY *pkey = NULL;

	ENGINE_load_builtin_engines();
	e = ENGINE_by_id(engine);

	if (!e) {
		fprintf(stderr, "Failed to load engine: %s\n", engine);
		ERR_print_errors_fp(stderr);
		return NULL;
	}

	ui = UI_create_method("sbsigntools");
	if (!ui) {
		fprintf(stderr, "Failed to create UI method\n");
		ERR_print_errors_fp(stderr);
		goto out_free;
	}
	UI_method_set_reader(ui, ui_read);

	if (!ENGINE_init(e)) {
		fprintf(stderr, "Failed to initialize engine %s\n", engine);
		ERR_print_errors_fp(stderr);
		goto out_free;
	}

	pkey = ENGINE_load_private_key(e, keyfile, ui, NULL);
	ENGINE_finish(e);

 out_free:
	ENGINE_free(e);
	return pkey;
}

EVP_PKEY *
read_private_key(char *engine, char *keyfile)
{
	if (engine)
		return read_engine_private_key(engine, keyfile);
	else
		return read_pem_private_key(keyfile);
}