| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- 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;
- }
|