chromium/device/fido/enclave/enclave_protocol_utils.h

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef DEVICE_FIDO_ENCLAVE_ENCLAVE_PROTOCOL_UTILS_H_
#define DEVICE_FIDO_ENCLAVE_ENCLAVE_PROTOCOL_UTILS_H_

#include <optional>
#include <string>
#include <utility>
#include <vector>

#include "base/component_export.h"
#include "base/containers/span.h"
#include "base/functional/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "device/fido/authenticator_get_assertion_response.h"
#include "device/fido/authenticator_make_credential_response.h"
#include "device/fido/ctap_get_assertion_request.h"
#include "device/fido/ctap_make_credential_request.h"
#include "device/fido/enclave/types.h"
#include "third_party/abseil-cpp/absl/types/variant.h"

namespace sync_pb {
class WebauthnCredentialSpecifics;
}

namespace cbor {
class Value;
}

namespace device {

class JSONRequest;

namespace enclave {

// Represents an error encountered while parsing a response from the enclave
// service. This can be parsing errors or specified errors returned from the
// service.
// If the service returned an error response, `index` indicates which response
// in the array contained the error. `index` is -1 if there was an error
// parsing the response.
// `error_code` when present represents a code received in an error response
// from the enclave. `error_string` when present represents a string received in
// an error response from the enclave, or a description of the parsing error
// encountered.
struct COMPONENT_EXPORT(DEVICE_FIDO) ErrorResponse {};

// Parses a decrypted assertion command response from the enclave.
// If there are multiple request responses in the array, it assumes the last
// one is for the GetAssertion.
// Returns one of: A successful response, or a struct containing details of
//                 the error.
absl::variant<AuthenticatorGetAssertionResponse, ErrorResponse>
    COMPONENT_EXPORT(DEVICE_FIDO)
        ParseGetAssertionResponse(cbor::Value response_value,
                                  base::span<const uint8_t> credential_id);

// Parses a decrypted registration command response from the enclave.
// If there are multiple request responses in the array, it assumes the last
// one is for the MakeCredential.
// Returns one of: A pair containing the response and the new passkey entity,
//                 a struct containing details of the error.
absl::variant<std::pair<AuthenticatorMakeCredentialResponse,
                        sync_pb::WebauthnCredentialSpecifics>,
              ErrorResponse>
    COMPONENT_EXPORT(DEVICE_FIDO)
        ParseMakeCredentialResponse(cbor::Value response,
                                    const CtapMakeCredentialRequest& request,
                                    int32_t wrapped_secret_version,
                                    bool user_verified);

// Returns a CBOR value with the provided GetAssertion request and associated
// passkey. The return value can be serialized into a Command request according
// to the enclave protocol.
cbor::Value COMPONENT_EXPORT(DEVICE_FIDO) BuildGetAssertionCommand(
    const sync_pb::WebauthnCredentialSpecifics& passkey,
    scoped_refptr<JSONRequest> request,
    std::string client_data_hash,
    std::unique_ptr<ClaimedPIN> claimed_pin,
    std::optional<std::vector<uint8_t>> wrapped_secret,
    std::optional<std::vector<uint8_t>> secret);

// Returns a CBOR value with the provided MakeCredential request. The return
// value can be serialized into a Command request according to the enclave
// protocol.
cbor::Value COMPONENT_EXPORT(DEVICE_FIDO) BuildMakeCredentialCommand(
    scoped_refptr<JSONRequest> request,
    std::unique_ptr<ClaimedPIN> claimed_pin,
    std::optional<std::vector<uint8_t>> wrapped_secret,
    std::optional<std::vector<uint8_t>> secret);

// Returns a CBOR value with the provided AddUVKey command to the enclave.
// It must precede a credential registration or assertion request in the
// command array.
cbor::Value COMPONENT_EXPORT(DEVICE_FIDO)
    BuildAddUVKeyCommand(base::span<const uint8_t> uv_public_key);

// Builds a CBOR serialization of the command to be sent to the enclave
// service which can then be encrypted and sent over HTTPS.
//
// |command| is either an array (in which case it is used directly) or another
//     type of object (in which case it will be wrapped in a 1-element array).
// |signing_callback| is used to generate the signature over the encoded
//     command using the protected private key. It can be null if the command
//     does not need to be authenticated.
// |handshake_hash| is the 32-byte hash from the Noise handshake.
// |complete_callback| is invoked with the finished serialized command.
void COMPONENT_EXPORT(DEVICE_FIDO) BuildCommandRequestBody(
    cbor::Value command,
    SigningCallback signing_callback,
    base::span<const uint8_t, crypto::kSHA256Length> handshake_hash,
    base::OnceCallback<void(std::optional<std::vector<uint8_t>>)>
        complete_callback);

}  // namespace enclave

}  // namespace device

#endif  // DEVICE_FIDO_ENCLAVE_ENCLAVE_PROTOCOL_UTILS_H_