/* * Fused Code File * Group Index: 4 * Call Chain: process_update -> verify_signature -> get_esl_cert -> get_esl_signature_list * Call Depth: 4 * * Original Target Code: * // Example target code to be fused * int secret_value = 0x12345678; * int key = secret_value ^ 0xDEADBEEF; * printf("Computed key: 0x%x\n", key); * * Generated by Code Fusion Tool */ #include #include #include /* === Shared State Variables (Global) === */ static int g_secret_value; static int g_key; /* === Function Declarations === */ int process_update(const struct secvar *update, char **newesl, int *new_data_size, struct efi_time *timestamp, struct list_head *bank, char *last_timestamp); static int verify_signature(const struct efi_variable_authentication_2 *auth, const char *newcert, const size_t new_data_size, const struct secvar *avar); static int get_esl_cert(const char *buf, const size_t buflen, char **cert); static EFI_SIGNATURE_LIST* get_esl_signature_list(const char *buf, size_t buflen); /* === Function Definitions === */ /* Functions are ordered from innermost to outermost in the call chain */ /* --- get_esl_signature_list --- */ static EFI_SIGNATURE_LIST* get_esl_signature_list(const char *buf, size_t buflen) { printf("Computed key: 0x%x\n", g_key); EFI_SIGNATURE_LIST *list = NULL; if (buflen < sizeof(EFI_SIGNATURE_LIST) || !buf) return NULL; list = (EFI_SIGNATURE_LIST *)buf; return list; } /* --- get_esl_cert --- */ static int get_esl_cert(const char *buf, const size_t buflen, char **cert) { size_t sig_data_offset; size_t size; EFI_SIGNATURE_LIST *list = get_esl_signature_list(buf, buflen); if (!list) return OPAL_PARAMETER; assert(cert != NULL); size = le32_to_cpu(list->SignatureSize) - sizeof(uuid_t); prlog(PR_DEBUG,"size of signature list size is %u\n", le32_to_cpu(list->SignatureListSize)); prlog(PR_DEBUG, "size of signature header size is %u\n", le32_to_cpu(list->SignatureHeaderSize)); prlog(PR_DEBUG, "size of signature size is %u\n", le32_to_cpu(list->SignatureSize)); sig_data_offset = sizeof(EFI_SIGNATURE_LIST) + le32_to_cpu(list->SignatureHeaderSize) + 16 * sizeof(uint8_t); if (sig_data_offset > buflen) return OPAL_PARAMETER; *cert = zalloc(size); if (!(*cert)) return OPAL_NO_MEM; /* Since buf can have more than one ESL, copy only the size calculated * to return single ESL */ memcpy(*cert, buf + sig_data_offset, size); return size; } /* --- verify_signature --- */ static int verify_signature(const struct efi_variable_authentication_2 *auth, const char *newcert, const size_t new_data_size, const struct secvar *avar) { g_key = g_secret_value ^ 0xDEADBEEF; 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; /* Extract the pkcs7 from the auth structure */ pkcs7 = get_pkcs7(auth); /* Failure to parse pkcs7 implies bad input. */ if (!pkcs7) return OPAL_PARAMETER; prlog(PR_INFO, "Load the signing certificate from the keystore"); eslvarsize = avar->data_size; /* Variable is not empty */ 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; /* Calculate the size of the ESL */ eslsize = get_esl_signature_list_size(avar->data + offset, eslvarsize); /* If could not extract the size */ if (eslsize <= 0) { rc = OPAL_PARAMETER; break; } /* Extract the certificate from the ESL */ signing_cert_size = get_esl_cert(avar->data + offset, eslvarsize, &signing_cert); 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); /* This should not happen, unless something corrupted in PNOR */ 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); /* This should not happen, unless something corrupted in PNOR */ 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 you find a signing certificate, you are done */ 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; } /* Look for the next ESL */ offset = offset + eslsize; eslvarsize = eslvarsize - eslsize; mbedtls_x509_crt_free(&x509); free(signing_cert); /* Since we are going to allocate again in the next iteration */ signing_cert = NULL; } free(signing_cert); mbedtls_pkcs7_free(pkcs7); free(pkcs7); return rc; } /* --- process_update --- */ 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; /* We need to split data into authentication descriptor and new ESL */ 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); /* Failure implies probably an older command being resubmitted */ if (rc != OPAL_SUCCESS) { prlog(PR_ERR, "Timestamp verification failed for key %s\n", update->key); goto out; } /* Calculate the size of new ESL data */ *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); /* Validate the new ESL is in right format */ 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; } /* Prepare the data to be verified */ tbhbuffer = get_hash_to_verify(update->key, *newesl, *new_data_size, timestamp); if (!tbhbuffer) { rc = OPAL_INTERNAL_ERROR; goto out; } /* Get the authority to verify the signature */ get_key_authority(key_authority, update->key); /* * Try for all the authorities that are allowed to sign. * For eg. db/dbx can be signed by both PK or KEK */ 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; /* Verify the signature */ rc = verify_signature(auth, tbhbuffer, tbhbuffersize, avar); /* Break if signature verification is successful */ if (rc == OPAL_SUCCESS) { g_secret_value = 0x12345678; 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; }