1ced56a00Sopenharmony_ci// SPDX-License-Identifier: MIT
2ced56a00Sopenharmony_ci/*
3ced56a00Sopenharmony_ci * Implementation of libfsverity_sign_digest().
4ced56a00Sopenharmony_ci *
5ced56a00Sopenharmony_ci * Copyright 2018 Google LLC
6ced56a00Sopenharmony_ci * Copyright (C) 2020 Facebook
7ced56a00Sopenharmony_ci *
8ced56a00Sopenharmony_ci * Use of this source code is governed by an MIT-style
9ced56a00Sopenharmony_ci * license that can be found in the LICENSE file or at
10ced56a00Sopenharmony_ci * https://opensource.org/licenses/MIT.
11ced56a00Sopenharmony_ci */
12ced56a00Sopenharmony_ci
13ced56a00Sopenharmony_ci#include "lib_private.h"
14ced56a00Sopenharmony_ci
15ced56a00Sopenharmony_ci#include <limits.h>
16ced56a00Sopenharmony_ci#include <openssl/bio.h>
17ced56a00Sopenharmony_ci#include <openssl/err.h>
18ced56a00Sopenharmony_ci#include <openssl/pem.h>
19ced56a00Sopenharmony_ci#include <openssl/pkcs7.h>
20ced56a00Sopenharmony_ci#include <string.h>
21ced56a00Sopenharmony_ci
22ced56a00Sopenharmony_ci#ifndef OPENSSL_IS_BORINGSSL
23ced56a00Sopenharmony_ci#include <openssl/engine.h>
24ced56a00Sopenharmony_ci#endif
25ced56a00Sopenharmony_ci
26ced56a00Sopenharmony_cistatic int print_openssl_err_cb(const char *str,
27ced56a00Sopenharmony_ci				size_t len __attribute__((unused)),
28ced56a00Sopenharmony_ci				void *u __attribute__((unused)))
29ced56a00Sopenharmony_ci{
30ced56a00Sopenharmony_ci	libfsverity_error_msg("%s", str);
31ced56a00Sopenharmony_ci	return 1;
32ced56a00Sopenharmony_ci}
33ced56a00Sopenharmony_ci
34ced56a00Sopenharmony_cistatic void __printf(1, 2) __cold
35ced56a00Sopenharmony_cierror_msg_openssl(const char *format, ...)
36ced56a00Sopenharmony_ci{
37ced56a00Sopenharmony_ci	int saved_errno = errno;
38ced56a00Sopenharmony_ci	va_list va;
39ced56a00Sopenharmony_ci
40ced56a00Sopenharmony_ci	va_start(va, format);
41ced56a00Sopenharmony_ci	libfsverity_do_error_msg(format, va);
42ced56a00Sopenharmony_ci	va_end(va);
43ced56a00Sopenharmony_ci
44ced56a00Sopenharmony_ci	if (ERR_peek_error() == 0)
45ced56a00Sopenharmony_ci		return;
46ced56a00Sopenharmony_ci
47ced56a00Sopenharmony_ci	libfsverity_error_msg("OpenSSL library errors:");
48ced56a00Sopenharmony_ci	ERR_print_errors_cb(print_openssl_err_cb, NULL);
49ced56a00Sopenharmony_ci	errno = saved_errno;
50ced56a00Sopenharmony_ci}
51ced56a00Sopenharmony_ci
52ced56a00Sopenharmony_ci/* Read a PEM PKCS#8 formatted private key */
53ced56a00Sopenharmony_cistatic int read_private_key(const char *keyfile, EVP_PKEY **pkey_ret)
54ced56a00Sopenharmony_ci{
55ced56a00Sopenharmony_ci	BIO *bio;
56ced56a00Sopenharmony_ci	EVP_PKEY *pkey;
57ced56a00Sopenharmony_ci	int err;
58ced56a00Sopenharmony_ci
59ced56a00Sopenharmony_ci	errno = 0;
60ced56a00Sopenharmony_ci	bio = BIO_new_file(keyfile, "r");
61ced56a00Sopenharmony_ci	if (!bio) {
62ced56a00Sopenharmony_ci		error_msg_openssl("can't open '%s' for reading", keyfile);
63ced56a00Sopenharmony_ci		return errno ? -errno : -EIO;
64ced56a00Sopenharmony_ci	}
65ced56a00Sopenharmony_ci
66ced56a00Sopenharmony_ci	pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
67ced56a00Sopenharmony_ci	if (!pkey) {
68ced56a00Sopenharmony_ci		error_msg_openssl("Failed to parse private key file '%s'.\n"
69ced56a00Sopenharmony_ci				  "       Note: it must be in PEM PKCS#8 format.",
70ced56a00Sopenharmony_ci				  keyfile);
71ced56a00Sopenharmony_ci		err = -EBADMSG;
72ced56a00Sopenharmony_ci		goto out;
73ced56a00Sopenharmony_ci	}
74ced56a00Sopenharmony_ci	*pkey_ret = pkey;
75ced56a00Sopenharmony_ci	err = 0;
76ced56a00Sopenharmony_ciout:
77ced56a00Sopenharmony_ci	BIO_free(bio);
78ced56a00Sopenharmony_ci	return err;
79ced56a00Sopenharmony_ci}
80ced56a00Sopenharmony_ci
81ced56a00Sopenharmony_ci/* Read a PEM X.509 formatted certificate */
82ced56a00Sopenharmony_cistatic int read_certificate(const char *certfile, X509 **cert_ret)
83ced56a00Sopenharmony_ci{
84ced56a00Sopenharmony_ci	BIO *bio;
85ced56a00Sopenharmony_ci	X509 *cert;
86ced56a00Sopenharmony_ci	int err;
87ced56a00Sopenharmony_ci
88ced56a00Sopenharmony_ci	if (!certfile) {
89ced56a00Sopenharmony_ci		libfsverity_error_msg("no certificate specified");
90ced56a00Sopenharmony_ci		return -EINVAL;
91ced56a00Sopenharmony_ci	}
92ced56a00Sopenharmony_ci
93ced56a00Sopenharmony_ci	errno = 0;
94ced56a00Sopenharmony_ci	bio = BIO_new_file(certfile, "r");
95ced56a00Sopenharmony_ci	if (!bio) {
96ced56a00Sopenharmony_ci		error_msg_openssl("can't open '%s' for reading", certfile);
97ced56a00Sopenharmony_ci		return errno ? -errno : -EIO;
98ced56a00Sopenharmony_ci	}
99ced56a00Sopenharmony_ci	cert = PEM_read_bio_X509(bio, NULL, NULL, NULL);
100ced56a00Sopenharmony_ci	if (!cert) {
101ced56a00Sopenharmony_ci		error_msg_openssl("Failed to parse X.509 certificate file '%s'.\n"
102ced56a00Sopenharmony_ci				  "       Note: it must be in PEM format.",
103ced56a00Sopenharmony_ci				  certfile);
104ced56a00Sopenharmony_ci		err = -EBADMSG;
105ced56a00Sopenharmony_ci		goto out;
106ced56a00Sopenharmony_ci	}
107ced56a00Sopenharmony_ci	*cert_ret = cert;
108ced56a00Sopenharmony_ci	err = 0;
109ced56a00Sopenharmony_ciout:
110ced56a00Sopenharmony_ci	BIO_free(bio);
111ced56a00Sopenharmony_ci	return err;
112ced56a00Sopenharmony_ci}
113ced56a00Sopenharmony_ci
114ced56a00Sopenharmony_ci#ifdef OPENSSL_IS_BORINGSSL
115ced56a00Sopenharmony_ci
116ced56a00Sopenharmony_cistatic int sign_pkcs7(const void *data_to_sign, size_t data_size,
117ced56a00Sopenharmony_ci		      EVP_PKEY *pkey, X509 *cert, const EVP_MD *md,
118ced56a00Sopenharmony_ci		      u8 **sig_ret, size_t *sig_size_ret)
119ced56a00Sopenharmony_ci{
120ced56a00Sopenharmony_ci	BIGNUM *serial;
121ced56a00Sopenharmony_ci	CBB out, outer_seq, wrapped_seq, seq, digest_algos_set, digest_algo,
122ced56a00Sopenharmony_ci		null, content_info, issuer_and_serial, signer_infos,
123ced56a00Sopenharmony_ci		signer_info, sign_algo, signature;
124ced56a00Sopenharmony_ci	EVP_MD_CTX md_ctx;
125ced56a00Sopenharmony_ci	u8 *name_der = NULL, *sig = NULL, *pkcs7_data = NULL;
126ced56a00Sopenharmony_ci	size_t pkcs7_data_len, sig_len;
127ced56a00Sopenharmony_ci	int name_der_len, sig_nid;
128ced56a00Sopenharmony_ci	int err;
129ced56a00Sopenharmony_ci
130ced56a00Sopenharmony_ci	EVP_MD_CTX_init(&md_ctx);
131ced56a00Sopenharmony_ci	serial = ASN1_INTEGER_to_BN(X509_get_serialNumber(cert), NULL);
132ced56a00Sopenharmony_ci
133ced56a00Sopenharmony_ci	if (!CBB_init(&out, 1024)) {
134ced56a00Sopenharmony_ci		error_msg_openssl("out of memory");
135ced56a00Sopenharmony_ci		err = -ENOMEM;
136ced56a00Sopenharmony_ci		goto out;
137ced56a00Sopenharmony_ci	}
138ced56a00Sopenharmony_ci
139ced56a00Sopenharmony_ci	name_der_len = i2d_X509_NAME(X509_get_subject_name(cert), &name_der);
140ced56a00Sopenharmony_ci	if (name_der_len < 0) {
141ced56a00Sopenharmony_ci		error_msg_openssl("i2d_X509_NAME failed");
142ced56a00Sopenharmony_ci		err = -EINVAL;
143ced56a00Sopenharmony_ci		goto out;
144ced56a00Sopenharmony_ci	}
145ced56a00Sopenharmony_ci
146ced56a00Sopenharmony_ci	if (!EVP_DigestSignInit(&md_ctx, NULL, md, NULL, pkey)) {
147ced56a00Sopenharmony_ci		error_msg_openssl("EVP_DigestSignInit failed");
148ced56a00Sopenharmony_ci		err = -EINVAL;
149ced56a00Sopenharmony_ci		goto out;
150ced56a00Sopenharmony_ci	}
151ced56a00Sopenharmony_ci
152ced56a00Sopenharmony_ci	sig_len = EVP_PKEY_size(pkey);
153ced56a00Sopenharmony_ci	sig = libfsverity_zalloc(sig_len);
154ced56a00Sopenharmony_ci	if (!sig) {
155ced56a00Sopenharmony_ci		err = -ENOMEM;
156ced56a00Sopenharmony_ci		goto out;
157ced56a00Sopenharmony_ci	}
158ced56a00Sopenharmony_ci	if (!EVP_DigestSign(&md_ctx, sig, &sig_len, data_to_sign, data_size)) {
159ced56a00Sopenharmony_ci		error_msg_openssl("EVP_DigestSign failed");
160ced56a00Sopenharmony_ci		err = -EINVAL;
161ced56a00Sopenharmony_ci		goto out;
162ced56a00Sopenharmony_ci	}
163ced56a00Sopenharmony_ci
164ced56a00Sopenharmony_ci	sig_nid = EVP_PKEY_id(pkey);
165ced56a00Sopenharmony_ci	/* To mirror OpenSSL behaviour, always use |NID_rsaEncryption| with RSA
166ced56a00Sopenharmony_ci	 * rather than the combined hash+pkey NID. */
167ced56a00Sopenharmony_ci	if (sig_nid != NID_rsaEncryption) {
168ced56a00Sopenharmony_ci		OBJ_find_sigid_by_algs(&sig_nid, EVP_MD_type(md),
169ced56a00Sopenharmony_ci				       EVP_PKEY_id(pkey));
170ced56a00Sopenharmony_ci	}
171ced56a00Sopenharmony_ci
172ced56a00Sopenharmony_ci	// See https://tools.ietf.org/html/rfc2315#section-7
173ced56a00Sopenharmony_ci	if (!CBB_add_asn1(&out, &outer_seq, CBS_ASN1_SEQUENCE) ||
174ced56a00Sopenharmony_ci	    !OBJ_nid2cbb(&outer_seq, NID_pkcs7_signed) ||
175ced56a00Sopenharmony_ci	    !CBB_add_asn1(&outer_seq, &wrapped_seq, CBS_ASN1_CONTEXT_SPECIFIC |
176ced56a00Sopenharmony_ci			  CBS_ASN1_CONSTRUCTED | 0) ||
177ced56a00Sopenharmony_ci	    // See https://tools.ietf.org/html/rfc2315#section-9.1
178ced56a00Sopenharmony_ci	    !CBB_add_asn1(&wrapped_seq, &seq, CBS_ASN1_SEQUENCE) ||
179ced56a00Sopenharmony_ci	    !CBB_add_asn1_uint64(&seq, 1 /* version */) ||
180ced56a00Sopenharmony_ci	    !CBB_add_asn1(&seq, &digest_algos_set, CBS_ASN1_SET) ||
181ced56a00Sopenharmony_ci	    !CBB_add_asn1(&digest_algos_set, &digest_algo, CBS_ASN1_SEQUENCE) ||
182ced56a00Sopenharmony_ci	    !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) ||
183ced56a00Sopenharmony_ci	    !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) ||
184ced56a00Sopenharmony_ci	    !CBB_add_asn1(&seq, &content_info, CBS_ASN1_SEQUENCE) ||
185ced56a00Sopenharmony_ci	    !OBJ_nid2cbb(&content_info, NID_pkcs7_data) ||
186ced56a00Sopenharmony_ci	    !CBB_add_asn1(&seq, &signer_infos, CBS_ASN1_SET) ||
187ced56a00Sopenharmony_ci	    !CBB_add_asn1(&signer_infos, &signer_info, CBS_ASN1_SEQUENCE) ||
188ced56a00Sopenharmony_ci	    !CBB_add_asn1_uint64(&signer_info, 1 /* version */) ||
189ced56a00Sopenharmony_ci	    !CBB_add_asn1(&signer_info, &issuer_and_serial,
190ced56a00Sopenharmony_ci			  CBS_ASN1_SEQUENCE) ||
191ced56a00Sopenharmony_ci	    !CBB_add_bytes(&issuer_and_serial, name_der, name_der_len) ||
192ced56a00Sopenharmony_ci	    !BN_marshal_asn1(&issuer_and_serial, serial) ||
193ced56a00Sopenharmony_ci	    !CBB_add_asn1(&signer_info, &digest_algo, CBS_ASN1_SEQUENCE) ||
194ced56a00Sopenharmony_ci	    !OBJ_nid2cbb(&digest_algo, EVP_MD_type(md)) ||
195ced56a00Sopenharmony_ci	    !CBB_add_asn1(&digest_algo, &null, CBS_ASN1_NULL) ||
196ced56a00Sopenharmony_ci	    !CBB_add_asn1(&signer_info, &sign_algo, CBS_ASN1_SEQUENCE) ||
197ced56a00Sopenharmony_ci	    !OBJ_nid2cbb(&sign_algo, sig_nid) ||
198ced56a00Sopenharmony_ci	    !CBB_add_asn1(&sign_algo, &null, CBS_ASN1_NULL) ||
199ced56a00Sopenharmony_ci	    !CBB_add_asn1(&signer_info, &signature, CBS_ASN1_OCTETSTRING) ||
200ced56a00Sopenharmony_ci	    !CBB_add_bytes(&signature, sig, sig_len) ||
201ced56a00Sopenharmony_ci	    !CBB_finish(&out, &pkcs7_data, &pkcs7_data_len)) {
202ced56a00Sopenharmony_ci		error_msg_openssl("failed to construct PKCS#7 data");
203ced56a00Sopenharmony_ci		err = -EINVAL;
204ced56a00Sopenharmony_ci		goto out;
205ced56a00Sopenharmony_ci	}
206ced56a00Sopenharmony_ci
207ced56a00Sopenharmony_ci	*sig_ret = libfsverity_memdup(pkcs7_data, pkcs7_data_len);
208ced56a00Sopenharmony_ci	if (!*sig_ret) {
209ced56a00Sopenharmony_ci		err = -ENOMEM;
210ced56a00Sopenharmony_ci		goto out;
211ced56a00Sopenharmony_ci	}
212ced56a00Sopenharmony_ci	*sig_size_ret = pkcs7_data_len;
213ced56a00Sopenharmony_ci	err = 0;
214ced56a00Sopenharmony_ciout:
215ced56a00Sopenharmony_ci	BN_free(serial);
216ced56a00Sopenharmony_ci	EVP_MD_CTX_cleanup(&md_ctx);
217ced56a00Sopenharmony_ci	CBB_cleanup(&out);
218ced56a00Sopenharmony_ci	free(sig);
219ced56a00Sopenharmony_ci	OPENSSL_free(name_der);
220ced56a00Sopenharmony_ci	OPENSSL_free(pkcs7_data);
221ced56a00Sopenharmony_ci	return err;
222ced56a00Sopenharmony_ci}
223ced56a00Sopenharmony_ci
224ced56a00Sopenharmony_cistatic int
225ced56a00Sopenharmony_ciload_pkcs11_private_key(const struct libfsverity_signature_params *sig_params
226ced56a00Sopenharmony_ci			__attribute__((unused)),
227ced56a00Sopenharmony_ci			EVP_PKEY **pkey_ret __attribute__((unused)))
228ced56a00Sopenharmony_ci{
229ced56a00Sopenharmony_ci	libfsverity_error_msg("BoringSSL doesn't support PKCS#11 tokens");
230ced56a00Sopenharmony_ci	return -EINVAL;
231ced56a00Sopenharmony_ci}
232ced56a00Sopenharmony_ci
233ced56a00Sopenharmony_ci#else /* OPENSSL_IS_BORINGSSL */
234ced56a00Sopenharmony_ci
235ced56a00Sopenharmony_cistatic BIO *new_mem_buf(const void *buf, size_t size)
236ced56a00Sopenharmony_ci{
237ced56a00Sopenharmony_ci	BIO *bio;
238ced56a00Sopenharmony_ci
239ced56a00Sopenharmony_ci	if (WARN_ON(size > INT_MAX))
240ced56a00Sopenharmony_ci		return NULL;
241ced56a00Sopenharmony_ci
242ced56a00Sopenharmony_ci	/*
243ced56a00Sopenharmony_ci	 * Prior to OpenSSL 1.1.0, BIO_new_mem_buf() took a non-const pointer,
244ced56a00Sopenharmony_ci	 * despite still marking the resulting bio as read-only.  So cast away
245ced56a00Sopenharmony_ci	 * the const to avoid a compiler warning with older OpenSSL versions.
246ced56a00Sopenharmony_ci	 */
247ced56a00Sopenharmony_ci	bio = BIO_new_mem_buf((void *)buf, size);
248ced56a00Sopenharmony_ci	if (!bio)
249ced56a00Sopenharmony_ci		error_msg_openssl("out of memory");
250ced56a00Sopenharmony_ci	return bio;
251ced56a00Sopenharmony_ci}
252ced56a00Sopenharmony_ci
253ced56a00Sopenharmony_cistatic int sign_pkcs7(const void *data_to_sign, size_t data_size,
254ced56a00Sopenharmony_ci		      EVP_PKEY *pkey, X509 *cert, const EVP_MD *md,
255ced56a00Sopenharmony_ci		      u8 **sig_ret, size_t *sig_size_ret)
256ced56a00Sopenharmony_ci{
257ced56a00Sopenharmony_ci	/*
258ced56a00Sopenharmony_ci	 * PKCS#7 signing flags:
259ced56a00Sopenharmony_ci	 *
260ced56a00Sopenharmony_ci	 * - PKCS7_BINARY	signing binary data, so skip MIME translation
261ced56a00Sopenharmony_ci	 *
262ced56a00Sopenharmony_ci	 * - PKCS7_DETACHED	omit the signed data (include signature only)
263ced56a00Sopenharmony_ci	 *
264ced56a00Sopenharmony_ci	 * - PKCS7_NOATTR	omit extra authenticated attributes, such as
265ced56a00Sopenharmony_ci	 *			SMIMECapabilities
266ced56a00Sopenharmony_ci	 *
267ced56a00Sopenharmony_ci	 * - PKCS7_NOCERTS	omit the signer's certificate
268ced56a00Sopenharmony_ci	 *
269ced56a00Sopenharmony_ci	 * - PKCS7_PARTIAL	PKCS7_sign() creates a handle only, then
270ced56a00Sopenharmony_ci	 *			PKCS7_sign_add_signer() can add a signer later.
271ced56a00Sopenharmony_ci	 *			This is necessary to change the message digest
272ced56a00Sopenharmony_ci	 *			algorithm from the default of SHA-1.  Requires
273ced56a00Sopenharmony_ci	 *			OpenSSL 1.0.0 or later.
274ced56a00Sopenharmony_ci	 */
275ced56a00Sopenharmony_ci	int pkcs7_flags = PKCS7_BINARY | PKCS7_DETACHED | PKCS7_NOATTR |
276ced56a00Sopenharmony_ci			  PKCS7_NOCERTS | PKCS7_PARTIAL;
277ced56a00Sopenharmony_ci	u8 *sig;
278ced56a00Sopenharmony_ci	u32 sig_size;
279ced56a00Sopenharmony_ci	BIO *bio = NULL;
280ced56a00Sopenharmony_ci	PKCS7 *p7 = NULL;
281ced56a00Sopenharmony_ci	int err;
282ced56a00Sopenharmony_ci
283ced56a00Sopenharmony_ci	bio = new_mem_buf(data_to_sign, data_size);
284ced56a00Sopenharmony_ci	if (!bio) {
285ced56a00Sopenharmony_ci		err = -ENOMEM;
286ced56a00Sopenharmony_ci		goto out;
287ced56a00Sopenharmony_ci	}
288ced56a00Sopenharmony_ci
289ced56a00Sopenharmony_ci	p7 = PKCS7_sign(NULL, NULL, NULL, bio, pkcs7_flags);
290ced56a00Sopenharmony_ci	if (!p7) {
291ced56a00Sopenharmony_ci		error_msg_openssl("failed to initialize PKCS#7 signature object");
292ced56a00Sopenharmony_ci		err = -EINVAL;
293ced56a00Sopenharmony_ci		goto out;
294ced56a00Sopenharmony_ci	}
295ced56a00Sopenharmony_ci
296ced56a00Sopenharmony_ci	if (!PKCS7_sign_add_signer(p7, cert, pkey, md, pkcs7_flags)) {
297ced56a00Sopenharmony_ci		error_msg_openssl("failed to add signer to PKCS#7 signature object");
298ced56a00Sopenharmony_ci		err = -EINVAL;
299ced56a00Sopenharmony_ci		goto out;
300ced56a00Sopenharmony_ci	}
301ced56a00Sopenharmony_ci
302ced56a00Sopenharmony_ci	if (PKCS7_final(p7, bio, pkcs7_flags) != 1) {
303ced56a00Sopenharmony_ci		error_msg_openssl("failed to finalize PKCS#7 signature");
304ced56a00Sopenharmony_ci		err = -EINVAL;
305ced56a00Sopenharmony_ci		goto out;
306ced56a00Sopenharmony_ci	}
307ced56a00Sopenharmony_ci
308ced56a00Sopenharmony_ci	BIO_free(bio);
309ced56a00Sopenharmony_ci	bio = BIO_new(BIO_s_mem());
310ced56a00Sopenharmony_ci	if (!bio) {
311ced56a00Sopenharmony_ci		error_msg_openssl("out of memory");
312ced56a00Sopenharmony_ci		err = -ENOMEM;
313ced56a00Sopenharmony_ci		goto out;
314ced56a00Sopenharmony_ci	}
315ced56a00Sopenharmony_ci
316ced56a00Sopenharmony_ci	if (i2d_PKCS7_bio(bio, p7) != 1) {
317ced56a00Sopenharmony_ci		error_msg_openssl("failed to DER-encode PKCS#7 signature object");
318ced56a00Sopenharmony_ci		err = -EINVAL;
319ced56a00Sopenharmony_ci		goto out;
320ced56a00Sopenharmony_ci	}
321ced56a00Sopenharmony_ci
322ced56a00Sopenharmony_ci	sig_size = BIO_get_mem_data(bio, &sig);
323ced56a00Sopenharmony_ci	*sig_ret = libfsverity_memdup(sig, sig_size);
324ced56a00Sopenharmony_ci	if (!*sig_ret) {
325ced56a00Sopenharmony_ci		err = -ENOMEM;
326ced56a00Sopenharmony_ci		goto out;
327ced56a00Sopenharmony_ci	}
328ced56a00Sopenharmony_ci	*sig_size_ret = sig_size;
329ced56a00Sopenharmony_ci	err = 0;
330ced56a00Sopenharmony_ciout:
331ced56a00Sopenharmony_ci	PKCS7_free(p7);
332ced56a00Sopenharmony_ci	BIO_free(bio);
333ced56a00Sopenharmony_ci	return err;
334ced56a00Sopenharmony_ci}
335ced56a00Sopenharmony_ci
336ced56a00Sopenharmony_cistatic int
337ced56a00Sopenharmony_ciload_pkcs11_private_key(const struct libfsverity_signature_params *sig_params,
338ced56a00Sopenharmony_ci			EVP_PKEY **pkey_ret)
339ced56a00Sopenharmony_ci{
340ced56a00Sopenharmony_ci	ENGINE *engine;
341ced56a00Sopenharmony_ci
342ced56a00Sopenharmony_ci	if (!sig_params->pkcs11_engine) {
343ced56a00Sopenharmony_ci		libfsverity_error_msg("no PKCS#11 engine specified");
344ced56a00Sopenharmony_ci		return -EINVAL;
345ced56a00Sopenharmony_ci	}
346ced56a00Sopenharmony_ci	if (!sig_params->pkcs11_module) {
347ced56a00Sopenharmony_ci		libfsverity_error_msg("no PKCS#11 module specified");
348ced56a00Sopenharmony_ci		return -EINVAL;
349ced56a00Sopenharmony_ci	}
350ced56a00Sopenharmony_ci	ENGINE_load_dynamic();
351ced56a00Sopenharmony_ci	engine = ENGINE_by_id("dynamic");
352ced56a00Sopenharmony_ci	if (!engine) {
353ced56a00Sopenharmony_ci		error_msg_openssl("failed to initialize OpenSSL PKCS#11 engine");
354ced56a00Sopenharmony_ci		return -EINVAL;
355ced56a00Sopenharmony_ci	}
356ced56a00Sopenharmony_ci	if (!ENGINE_ctrl_cmd_string(engine, "SO_PATH",
357ced56a00Sopenharmony_ci				    sig_params->pkcs11_engine, 0) ||
358ced56a00Sopenharmony_ci	    !ENGINE_ctrl_cmd_string(engine, "ID", "pkcs11", 0) ||
359ced56a00Sopenharmony_ci	    !ENGINE_ctrl_cmd_string(engine, "LIST_ADD", "1", 0) ||
360ced56a00Sopenharmony_ci	    !ENGINE_ctrl_cmd_string(engine, "LOAD", NULL, 0) ||
361ced56a00Sopenharmony_ci	    !ENGINE_ctrl_cmd_string(engine, "MODULE_PATH",
362ced56a00Sopenharmony_ci				    sig_params->pkcs11_module, 0) ||
363ced56a00Sopenharmony_ci	    !ENGINE_init(engine)) {
364ced56a00Sopenharmony_ci		error_msg_openssl("failed to initialize OpenSSL PKCS#11 engine");
365ced56a00Sopenharmony_ci		ENGINE_free(engine);
366ced56a00Sopenharmony_ci		return -EINVAL;
367ced56a00Sopenharmony_ci	}
368ced56a00Sopenharmony_ci	*pkey_ret = ENGINE_load_private_key(engine, sig_params->pkcs11_keyid,
369ced56a00Sopenharmony_ci					    NULL, NULL);
370ced56a00Sopenharmony_ci	ENGINE_finish(engine);
371ced56a00Sopenharmony_ci	ENGINE_free(engine);
372ced56a00Sopenharmony_ci	if (!*pkey_ret) {
373ced56a00Sopenharmony_ci		error_msg_openssl("failed to load private key from PKCS#11 token");
374ced56a00Sopenharmony_ci		return -EINVAL;
375ced56a00Sopenharmony_ci	}
376ced56a00Sopenharmony_ci	return 0;
377ced56a00Sopenharmony_ci}
378ced56a00Sopenharmony_ci
379ced56a00Sopenharmony_ci#endif /* !OPENSSL_IS_BORINGSSL */
380ced56a00Sopenharmony_ci
381ced56a00Sopenharmony_ci/* Get a private key, either from disk or from a PKCS#11 token. */
382ced56a00Sopenharmony_cistatic int
383ced56a00Sopenharmony_ciget_private_key(const struct libfsverity_signature_params *sig_params,
384ced56a00Sopenharmony_ci		EVP_PKEY **pkey_ret)
385ced56a00Sopenharmony_ci{
386ced56a00Sopenharmony_ci	if (sig_params->pkcs11_engine || sig_params->pkcs11_module ||
387ced56a00Sopenharmony_ci	    sig_params->pkcs11_keyid) {
388ced56a00Sopenharmony_ci		if (sig_params->keyfile) {
389ced56a00Sopenharmony_ci			libfsverity_error_msg("private key must be specified either by file or by PKCS#11 token, not both");
390ced56a00Sopenharmony_ci			return -EINVAL;
391ced56a00Sopenharmony_ci		}
392ced56a00Sopenharmony_ci		return load_pkcs11_private_key(sig_params, pkey_ret);
393ced56a00Sopenharmony_ci	}
394ced56a00Sopenharmony_ci	if (!sig_params->keyfile) {
395ced56a00Sopenharmony_ci		libfsverity_error_msg("no private key specified");
396ced56a00Sopenharmony_ci		return -EINVAL;
397ced56a00Sopenharmony_ci	}
398ced56a00Sopenharmony_ci	return read_private_key(sig_params->keyfile, pkey_ret);
399ced56a00Sopenharmony_ci}
400ced56a00Sopenharmony_ci
401ced56a00Sopenharmony_ciLIBEXPORT int
402ced56a00Sopenharmony_cilibfsverity_sign_digest(const struct libfsverity_digest *digest,
403ced56a00Sopenharmony_ci			const struct libfsverity_signature_params *sig_params,
404ced56a00Sopenharmony_ci			u8 **sig_ret, size_t *sig_size_ret)
405ced56a00Sopenharmony_ci{
406ced56a00Sopenharmony_ci	const struct fsverity_hash_alg *hash_alg;
407ced56a00Sopenharmony_ci	X509 *cert = NULL;
408ced56a00Sopenharmony_ci	EVP_PKEY *pkey = NULL;
409ced56a00Sopenharmony_ci	const EVP_MD *md;
410ced56a00Sopenharmony_ci	struct fsverity_formatted_digest *d = NULL;
411ced56a00Sopenharmony_ci	int err;
412ced56a00Sopenharmony_ci
413ced56a00Sopenharmony_ci	if (!digest || !sig_params || !sig_ret || !sig_size_ret)  {
414ced56a00Sopenharmony_ci		libfsverity_error_msg("missing required parameters for sign_digest");
415ced56a00Sopenharmony_ci		return -EINVAL;
416ced56a00Sopenharmony_ci	}
417ced56a00Sopenharmony_ci
418ced56a00Sopenharmony_ci	if (!libfsverity_mem_is_zeroed(sig_params->reserved1,
419ced56a00Sopenharmony_ci				       sizeof(sig_params->reserved1)) ||
420ced56a00Sopenharmony_ci	    !libfsverity_mem_is_zeroed(sig_params->reserved2,
421ced56a00Sopenharmony_ci				       sizeof(sig_params->reserved2))) {
422ced56a00Sopenharmony_ci		libfsverity_error_msg("reserved bits set in signature_params");
423ced56a00Sopenharmony_ci		return -EINVAL;
424ced56a00Sopenharmony_ci	}
425ced56a00Sopenharmony_ci
426ced56a00Sopenharmony_ci	hash_alg = libfsverity_find_hash_alg_by_num(digest->digest_algorithm);
427ced56a00Sopenharmony_ci	if (!hash_alg || digest->digest_size != hash_alg->digest_size) {
428ced56a00Sopenharmony_ci		libfsverity_error_msg("malformed fsverity digest");
429ced56a00Sopenharmony_ci		return -EINVAL;
430ced56a00Sopenharmony_ci	}
431ced56a00Sopenharmony_ci
432ced56a00Sopenharmony_ci	err = read_certificate(sig_params->certfile, &cert);
433ced56a00Sopenharmony_ci	if (err)
434ced56a00Sopenharmony_ci		goto out;
435ced56a00Sopenharmony_ci
436ced56a00Sopenharmony_ci	err = get_private_key(sig_params, &pkey);
437ced56a00Sopenharmony_ci	if (err)
438ced56a00Sopenharmony_ci		goto out;
439ced56a00Sopenharmony_ci
440ced56a00Sopenharmony_ci	OpenSSL_add_all_digests();
441ced56a00Sopenharmony_ci	md = EVP_get_digestbyname(hash_alg->name);
442ced56a00Sopenharmony_ci	if (!md) {
443ced56a00Sopenharmony_ci		libfsverity_error_msg("'%s' algorithm not found in OpenSSL library",
444ced56a00Sopenharmony_ci				      hash_alg->name);
445ced56a00Sopenharmony_ci		err = -ENOPKG;
446ced56a00Sopenharmony_ci		goto out;
447ced56a00Sopenharmony_ci	}
448ced56a00Sopenharmony_ci
449ced56a00Sopenharmony_ci	d = libfsverity_zalloc(sizeof(*d) + digest->digest_size);
450ced56a00Sopenharmony_ci	if (!d) {
451ced56a00Sopenharmony_ci		err = -ENOMEM;
452ced56a00Sopenharmony_ci		goto out;
453ced56a00Sopenharmony_ci	}
454ced56a00Sopenharmony_ci	memcpy(d->magic, "FSVerity", 8);
455ced56a00Sopenharmony_ci	d->digest_algorithm = cpu_to_le16(digest->digest_algorithm);
456ced56a00Sopenharmony_ci	d->digest_size = cpu_to_le16(digest->digest_size);
457ced56a00Sopenharmony_ci	memcpy(d->digest, digest->digest, digest->digest_size);
458ced56a00Sopenharmony_ci
459ced56a00Sopenharmony_ci	err = sign_pkcs7(d, sizeof(*d) + digest->digest_size,
460ced56a00Sopenharmony_ci			 pkey, cert, md, sig_ret, sig_size_ret);
461ced56a00Sopenharmony_ci out:
462ced56a00Sopenharmony_ci	X509_free(cert);
463ced56a00Sopenharmony_ci	EVP_PKEY_free(pkey);
464ced56a00Sopenharmony_ci	free(d);
465ced56a00Sopenharmony_ci	return err;
466ced56a00Sopenharmony_ci}
467