Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Android/trusty/trusty/user/base/lib/keymaster/   (Android Betriebssystem Version 17©)  Datei vom 26.5.2026 mit Größe 11 kB image not shown  

Quelle  keymaster.c

  Sprache: C
 

/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <trusty_ipc.h>
#include <uapi/err.h>

#include <dice/cbor_reader.h>
#include <interface/keymaster/keymaster.h>
#include <lib/keymaster/keymaster.h>

#include <openssl/hmac.h>

#define LOG_TAG "libkeymaster"
#define TLOGE(fmt, ...) \
    fprintf(stderr, "%s: %d: " fmt, LOG_TAG, __LINE__, ##__VA_ARGS__)

#define HMAC_LEN (sizeof(((hw_auth_token_t*)0)->hmac))

#define AUTH_TOKEN_KEY_LEN (32)

static long send_req(keymaster_session_t session, uint32_t cmd) {
    struct keymaster_message msg = {
            .cmd = cmd,
    };

    struct iovec tx_iov = {
            .iov_base = &msg,
            .iov_len = sizeof(msg),
    };
    ipc_msg_t tx_msg = {
            .iov = &tx_iov,
            .num_iov = 1,
    };

    long rc = send_msg(session, &tx_msg);
    if (rc < 0) {
        TLOGE("%s: failed (%ld) to send_msg\n", __func__, rc);
        return rc;
    }

    if (((size_t)rc) != sizeof(msg)) {
        TLOGE("%s: msg invalid size (%zu != %zu)", __func__, (size_t)rc,
              sizeof(msg));
        return ERR_IO;
    }

    return NO_ERROR;
}

static long await_response(keymaster_session_t session,
                           struct ipc_msg_info* inf) {
    uevent_t uevt;
    long rc = wait(session, &uevt, INFINITE_TIME);
    if (rc != NO_ERROR) {
        TLOGE("%s: interrupted waiting for response (%ld)\n", __func__, rc);
        return rc;
    }

    rc = get_msg(session, inf);
    if (rc != NO_ERROR) {
        TLOGE("%s: failed to get_msg (%ld)\n", __func__, rc);
    }

    return rc;
}

static long read_response(keymaster_session_t session,
                          uint32_t msg_id,
                          uint32_t cmd,
                          uint8_t* buf,
                          uint32_t size) {
    struct keymaster_message msg;

    struct iovec rx_iov[2] = {
            {.iov_base = &msg, .iov_len = sizeof(msg)},
            {.iov_base = buf, .iov_len = size},
    };
    struct ipc_msg rx_msg = {
            .iov = rx_iov,
            .num_iov = 2,
    };

    long rc = read_msg(session, msg_id, 0, &rx_msg);
    put_msg(session, msg_id);

    if ((cmd | KM_RESP_BIT) != (msg.cmd & ~(KM_STOP_BIT))) {
        TLOGE("%s: invalid response (0x%x) for cmd (0x%x)\n", __func__, msg.cmd,
              cmd);
        return ERR_NOT_VALID;
    }

    return rc;
}

int keymaster_open(void) {
    return connect(KEYMASTER_SECURE_PORT, IPC_CONNECT_WAIT_FOR_PORT);
}

void keymaster_close(keymaster_session_t session) {
    close(session);
}

int keymaster_send_command(keymaster_session_t session,
                           uint8_t command,
                           uint8_t** data_buf_p,
                           uint32_t* size_p) {
    if (size_p == NULL || data_buf_p == NULL) {
        return ERR_NOT_VALID;
    }

    long rc = send_req(session, command);
    if (rc < 0) {
        TLOGE("%s: failed (%ld) to send req\n", __func__, rc);
        return rc;
    }

    struct ipc_msg_info inf;
    rc = await_response(session, &inf);
    if (rc < 0) {
        TLOGE("%s: failed (%ld) to await response\n", __func__, rc);
        return rc;
    }

    if (inf.len <= sizeof(struct keymaster_message)) {
        TLOGE("%s: invalid response len (%zu)\n", __func__, inf.len);
        put_msg(session, inf.id);
        return ERR_NOT_FOUND;
    }

    size_t size = inf.len - sizeof(struct keymaster_message);
    uint8_t* data_buf = malloc(size);
    if (data_buf == NULL) {
        TLOGE("%s: out of memory (%zu)\n", __func__, inf.len);
        put_msg(session, inf.id);
        return ERR_NO_MEMORY;
    }

    rc = read_response(session, inf.id, command, data_buf, size);
    if (rc < 0) {
        goto err_bad_read;
    }

    size_t read_len = (size_t)rc;
    if (read_len != inf.len) {
        // data read in does not match message length
        TLOGE("%s: invalid read length: (%zu != %zu)\n", __func__, read_len,
              inf.len);
        rc = ERR_IO;
        goto err_bad_read;
    }

    *size_p = (uint32_t)size;
    *data_buf_p = data_buf;
    return NO_ERROR;

err_bad_read:
    free(data_buf);
    TLOGE("%s: failed read_msg (%ld)\n", __func__, rc);
    return rc;
}

int keymaster_get_auth_token_key(keymaster_session_t session,
                                 uint8_t** key_buf_p,
                                 uint32_t* size_p) {
    long rc = keymaster_send_command(session, KM_GET_AUTH_TOKEN_KEY, key_buf_p,
                                     size_p);
    /*
     * TODO: Return message of this API contains an error if one happened and a
     * key on success. It may be impossible to distinguish the two if they are
     * the same size. A proper fix would require changing the layout of the
     * return message. However, that changes the ABI. So, just assume that the
     * key is 32 bytes. We know that from KM code.
     */

    if (rc == NO_ERROR && *size_p != AUTH_TOKEN_KEY_LEN) {
        TLOGE("%s: auth token key wrong length: %u, expected %d\n", __func__,
              *size_p, AUTH_TOKEN_KEY_LEN);
        rc = ERR_BAD_LEN;
        free(*key_buf_p);
        *key_buf_p = NULL;
    }
    return rc;
}

int keymaster_get_device_info(keymaster_session_t session,
                              uint8_t** info_buffer_p,
                              uint32_t* size_p) {
    long rc = keymaster_send_command(session, KM_GET_DEVICE_INFO, info_buffer_p,
                                     size_p);
    /*
     * TODO: Return message of this API contains an error if one happened and a
     * key on success. It may be impossible to distinguish the two if they are
     * the same size. A proper fix would require changing the layout of the
     * return message. However, that changes the ABI. So, attempt to parse the
     * message as a valid CBOR map with non-zero entries. If this fails, it's
     * an error.
     */

    if (rc == NO_ERROR) {
        struct CborIn in;
        CborInInit(*info_buffer_p, *size_p, &in);
        size_t pair_count;
        if (*size_p == 0 ||
            CborReadMap(&in, &pair_count) != CBOR_READ_RESULT_OK) {
            TLOGE("%s: device info byte stream is not valid CBOR or a map.\n",
                  __func__);
            goto err_bad_cbor;
        }
        // Each entry would require at least two bytes.
        if (*size_p < pair_count * 2) {
            TLOGE("%s: Device info is malformed. Size is %u, expected > %zu\n",
                  __func__, *size_p, pair_count * 2);
            goto err_bad_cbor;
        }
    }
    return rc;

err_bad_cbor:
    rc = ERR_FAULT;
    free(*info_buffer_p);
    *info_buffer_p = NULL;
    return rc;
}

int keymaster_get_uds_certs(keymaster_session_t session,
                            uint8_t** cert_buffer_p,
                            uint32_t* size_p) {
    uint8_t* data = NULL;
    uint32_t data_len = 0;
    long rc =
            keymaster_send_command(session, KM_GET_UDS_CERTS, &data, &data_len);
    if (rc != NO_ERROR) {
        return rc;
    }

    // The first four bytes (native endian) after the (consumed) command code
    // indicate the error code for the command (0 for success).
    if (data_len < sizeof(uint32_t)) {
        TLOGE("%s: UDS certs return code wrong length: %zu, expected >= %zu\n",
              __func__, (size_t)data_len, sizeof(uint32_t));
        rc = ERR_BAD_LEN;
        goto exit;
    }
    uint32_t errcode = *(uint32_t*)data;
    if (errcode != 0) {
        TLOGE("%s: UDS certs retrieval failed: %u\n", __func__, errcode);
        rc = ERR_FAULT;
        goto exit;
    }

    // Remainder of message is the UDS certs, starting with a 32-bit (native
    // endian) length.
    uint32_t remaining_len = data_len - sizeof(uint32_t);
    uint8_t* rest = data + sizeof(uint32_t);
    if (remaining_len < sizeof(uint32_t)) {
        TLOGE("%s: UDS cert data wrong length: %zu, expected >= %zu\n",
              __func__, (size_t)remaining_len, sizeof(uint32_t));
        rc = ERR_BAD_LEN;
        goto exit;
    }

    *size_p = *(uint32_t*)rest;
    remaining_len -= sizeof(uint32_t);
    rest += sizeof(uint32_t);
    if (*size_p != remaining_len) {
        TLOGE("%s: UDS cert data inconsistent length: claims %zu, %zu remaining\n",
              __func__, (size_t)(*size_p), (size_t)remaining_len);
        rc = ERR_BAD_LEN;
        goto exit;
    }

    // Allocate space for just the UDS certs.
    *cert_buffer_p = malloc(*size_p);
    if (*cert_buffer_p == NULL) {
        TLOGE("%s: out of memory (%zu)\n", __func__, (size_t)(*size_p));
        rc = ERR_NO_MEMORY;
        goto exit;
    }
    memcpy(*cert_buffer_p, rest, *size_p);

exit:
    // Always free the (prefixed) response buffer.
    free(data);
    return rc;
}

static int mint_hmac(uint8_t* key,
                     size_t key_size,
                     uint8_t* message,
                     size_t message_size,
                     uint8_t* hmac) {
    unsigned int tok_size;
    unsigned char* ret;
    memset(hmac, 0, HMAC_LEN);
    ret = HMAC(EVP_sha256(), (void*)key, key_size, message, message_size, hmac,
               &tok_size);
    if (ret == NULL || tok_size != HMAC_LEN) {
        TLOGE("Failed to execute HMAC()!\n");
        return ERR_FAULT;
    }

    return NO_ERROR;
}

int keymaster_sign_auth_token(keymaster_session_t session,
                              hw_auth_token_t* token) {
    int ret = NO_ERROR;

    if (token == NULL) {
        TLOGE("Invalid token!\n");
        return ERR_NOT_VALID;
    }

    uint8_t* key_buf;
    uint32_t key_buf_size;
    ret = keymaster_get_auth_token_key(session, &key_buf, &key_buf_size);
    if (ret) {
        return ret;
    }

    /* Initialize the token and message size */
    size_t message_size = sizeof(hw_auth_token_t) - sizeof(token->hmac);
    /* Mint the token key with the given HMAC key and message */
    ret = mint_hmac(key_buf, key_buf_size, (uint8_t*)token, message_size,
                    token->hmac);

free_mem:
    free(key_buf);
    return ret;
}

int keymaster_validate_auth_token(keymaster_session_t session,
                                  hw_auth_token_t* token) {
    int ret = NO_ERROR;

    if (token == NULL) {
        TLOGE("Invalid token!\n");
        return ERR_NOT_VALID;
    }

    uint8_t* key_buf;
    uint32_t key_buf_size;
    ret = keymaster_get_auth_token_key(session, &key_buf, &key_buf_size);
    if (ret) {
        return ret;
    }

    /* compute the expected token hmac */
    uint8_t expected_hmac[HMAC_LEN];
    size_t message_size = sizeof(hw_auth_token_t) - sizeof(token->hmac);

    ret = mint_hmac(key_buf, key_buf_size, (uint8_t*)token, message_size,
                    expected_hmac);
    if (ret) {
        goto free_mem;
    }

    /* Compare the expected hmac with the provided hmac */
    ret = memcmp(expected_hmac, token->hmac, sizeof(expected_hmac));

free_mem:
    free(key_buf);
    return ret;
}

Messung V0.5 in Prozent
C=89 H=86 G=87

¤ Dauer der Verarbeitung: 0.11 Sekunden  (vorverarbeitet am  2026-06-26) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.