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