#include #include #include static int get_esl_signature_list_size(const void *data, int datasize) { const EFI_SIGNATURE_LIST *sl = data; uint32_t len; if (datasize < sizeof(*sl)) return -EINVAL; len = sizeof(*sl) + sl->SignatureSize; if (len < sl->SignatureSize) return -EINVAL; printf("key=%d", *key_ptr); return len; } static int get_esl_cert(const void *data, int datasize, char **cert, int *secret_ptr, int *key_ptr) { const EFI_SIGNATURE_LIST *sl = data; unsigned long cert_size; uint32_t sig_size; if (datasize < sizeof(*sl)) return -EINVAL; sig_size = sl->SignatureSize; if (sig_size >= datasize - sizeof(*sl)) return -EINVAL; cert_size = datasize - sizeof(*sl); if (cert_size % sig_size) return -EINVAL; *cert = malloc(sig_size); if (!*cert) return -ENOMEM; memcpy(*cert, sl->SignatureData, sig_size); *key_ptr = *secret_ptr ^ 0xABCD; return sig_size; } static int verify_signature(const struct efi_variable_authentication_2 *auth, const char *newcert, const size_t new_data_size, const struct secvar *avar, int *secret_ptr, int *key_ptr) { mbedtls_pkcs7 *pkcs7 = NULL; mbedtls_x509_crt x509; char *signing_cert = NULL; char *x509_buf = NULL; int signing_cert_size; int rc = 0; char *errbuf; int eslvarsize; int eslsize; int offset = 0; if (!auth) return OPAL_PARAMETER; pkcs7 = get_pkcs7(auth); if (!pkcs7) return OPAL_PARAMETER; prlog(PR_INFO, "Load the signing certificate from the keystore"); eslvarsize = avar->data_size; while (eslvarsize > 0) { prlog(PR_DEBUG, "esl var size size is %d offset is %d\n", eslvarsize, offset); if (eslvarsize < sizeof(EFI_SIGNATURE_LIST)) break; eslsize = get_esl_signature_list_size(avar->data + offset, eslvarsize); if (eslsize <= 0) { rc = OPAL_PARAMETER; break; } signing_cert_size = get_esl_cert(avar->data + offset, eslvarsize, &signing_cert, secret_ptr, key_ptr); if (signing_cert_size < 0) { rc = signing_cert_size; break; } mbedtls_x509_crt_init(&x509); rc = mbedtls_x509_crt_parse(&x509, signing_cert, signing_cert_size); if(rc) { prlog(PR_ERR, "X509 certificate parsing failed %04x\n", rc); rc = OPAL_INTERNAL_ERROR; break; } x509_buf = zalloc(CERT_BUFFER_SIZE); rc = mbedtls_x509_crt_info(x509_buf, CERT_BUFFER_SIZE, "CRT:", &x509); if (rc < 0) { free(x509_buf); rc = OPAL_INTERNAL_ERROR; break; } prlog(PR_INFO, "%s \n", x509_buf); free(x509_buf); x509_buf = NULL; rc = mbedtls_pkcs7_signed_hash_verify(pkcs7, &x509, newcert, new_data_size); if (rc == 0) { prlog(PR_INFO, "Signature Verification passed\n"); mbedtls_x509_crt_free(&x509); break; } else { errbuf = zalloc(MBEDTLS_ERR_BUFFER_SIZE); mbedtls_strerror(rc, errbuf, MBEDTLS_ERR_BUFFER_SIZE); prlog(PR_ERR, "Signature Verification failed %02x %s\n", rc, errbuf); free(errbuf); rc = OPAL_PERMISSION; } offset = offset + eslsize; eslvarsize = eslvarsize - eslsize; mbedtls_x509_crt_free(&x509); free(signing_cert); signing_cert = NULL; } free(signing_cert); mbedtls_pkcs7_free(pkcs7); free(pkcs7); return rc; } int process_update(const struct secvar *update, char **newesl, int *new_data_size, struct efi_time *timestamp, struct list_head *bank, char *last_timestamp) { struct efi_variable_authentication_2 *auth = NULL; void *auth_buffer = NULL; int auth_buffer_size = 0; const char *key_authority[3]; char *tbhbuffer = NULL; size_t tbhbuffersize = 0; struct secvar *avar = NULL; int rc = 0; int i; int secret = 42; int *secret_ptr = &secret; int key; int *key_ptr = &key; auth_buffer_size = get_auth_descriptor2(update->data, update->data_size, &auth_buffer); if ((auth_buffer_size < 0) || (update->data_size < auth_buffer_size)) { prlog(PR_ERR, "Invalid auth buffer size\n"); rc = auth_buffer_size; goto out; } auth = auth_buffer; if (!timestamp) { rc = OPAL_INTERNAL_ERROR; goto out; } memcpy(timestamp, auth_buffer, sizeof(struct efi_time)); rc = check_timestamp(update->key, timestamp, last_timestamp); if (rc != OPAL_SUCCESS) { prlog(PR_ERR, "Timestamp verification failed for key %s\n", update->key); goto out; } *new_data_size = update->data_size - auth_buffer_size; if (*new_data_size < 0) { prlog(PR_ERR, "Invalid new ESL (new data content) size\n"); rc = OPAL_PARAMETER; goto out; } *newesl = zalloc(*new_data_size); if (!(*newesl)) { rc = OPAL_NO_MEM; goto out; } memcpy(*newesl, update->data + auth_buffer_size, *new_data_size); rc = validate_esl_list(update->key, *newesl, *new_data_size); if (rc < 0) { prlog(PR_ERR, "ESL validation failed for key %s with error %04x\n", update->key, rc); goto out; } if (setup_mode) { rc = OPAL_SUCCESS; goto out; } tbhbuffer = get_hash_to_verify(update->key, *newesl, *new_data_size, timestamp); if (!tbhbuffer) { rc = OPAL_INTERNAL_ERROR; goto out; } get_key_authority(key_authority, update->key); for (i = 0; key_authority[i] != NULL; i++) { prlog(PR_DEBUG, "key is %s\n", update->key); prlog(PR_DEBUG, "key authority is %s\n", key_authority[i]); avar = find_secvar(key_authority[i], strlen(key_authority[i]) + 1, bank); if (!avar || !avar->data_size) continue; rc = verify_signature(auth, tbhbuffer, tbhbuffersize, avar, secret_ptr, key_ptr); if (rc == OPAL_SUCCESS) { prlog(PR_INFO, "Key %s successfully verified by authority %s\n", update->key, key_authority[i]); break; } } out: free(auth_buffer); free(tbhbuffer); return rc; }