blob: 99b3229e8826fbb02338c834742af5565d8475bb [file] [log] [blame]
/*
*
* Copyright 2015 gRPC authors.
*
* 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 <grpc/support/port_platform.h>
#include "src/core/tsi/transport_security.h"
#include <grpc/support/alloc.h>
#include <grpc/support/string_util.h>
#include <stdlib.h>
#include <string.h>
/* --- Tracing. --- */
grpc_core::TraceFlag tsi_tracing_enabled(false, "tsi");
/* --- tsi_result common implementation. --- */
const char* tsi_result_to_string(tsi_result result) {
switch (result) {
case TSI_OK:
return "TSI_OK";
case TSI_UNKNOWN_ERROR:
return "TSI_UNKNOWN_ERROR";
case TSI_INVALID_ARGUMENT:
return "TSI_INVALID_ARGUMENT";
case TSI_PERMISSION_DENIED:
return "TSI_PERMISSION_DENIED";
case TSI_INCOMPLETE_DATA:
return "TSI_INCOMPLETE_DATA";
case TSI_FAILED_PRECONDITION:
return "TSI_FAILED_PRECONDITION";
case TSI_UNIMPLEMENTED:
return "TSI_UNIMPLEMENTED";
case TSI_INTERNAL_ERROR:
return "TSI_INTERNAL_ERROR";
case TSI_DATA_CORRUPTED:
return "TSI_DATA_CORRUPTED";
case TSI_NOT_FOUND:
return "TSI_NOT_FOUND";
case TSI_PROTOCOL_FAILURE:
return "TSI_PROTOCOL_FAILURE";
case TSI_HANDSHAKE_IN_PROGRESS:
return "TSI_HANDSHAKE_IN_PROGRESS";
case TSI_OUT_OF_RESOURCES:
return "TSI_OUT_OF_RESOURCES";
case TSI_ASYNC:
return "TSI_ASYNC";
default:
return "UNKNOWN";
}
}
/* --- tsi_frame_protector common implementation. ---
Calls specific implementation after state/input validation. */
tsi_result tsi_frame_protector_protect(tsi_frame_protector* self,
const unsigned char* unprotected_bytes,
size_t* unprotected_bytes_size,
unsigned char* protected_output_frames,
size_t* protected_output_frames_size) {
if (self == nullptr || self->vtable == nullptr ||
unprotected_bytes == nullptr || unprotected_bytes_size == nullptr ||
protected_output_frames == nullptr ||
protected_output_frames_size == nullptr) {
return TSI_INVALID_ARGUMENT;
}
if (self->vtable->protect == nullptr) return TSI_UNIMPLEMENTED;
return self->vtable->protect(self, unprotected_bytes, unprotected_bytes_size,
protected_output_frames,
protected_output_frames_size);
}
tsi_result tsi_frame_protector_protect_flush(
tsi_frame_protector* self, unsigned char* protected_output_frames,
size_t* protected_output_frames_size, size_t* still_pending_size) {
if (self == nullptr || self->vtable == nullptr ||
protected_output_frames == nullptr ||
protected_output_frames_size == nullptr ||
still_pending_size == nullptr) {
return TSI_INVALID_ARGUMENT;
}
if (self->vtable->protect_flush == nullptr) return TSI_UNIMPLEMENTED;
return self->vtable->protect_flush(self, protected_output_frames,
protected_output_frames_size,
still_pending_size);
}
tsi_result tsi_frame_protector_unprotect(
tsi_frame_protector* self, const unsigned char* protected_frames_bytes,
size_t* protected_frames_bytes_size, unsigned char* unprotected_bytes,
size_t* unprotected_bytes_size) {
if (self == nullptr || self->vtable == nullptr ||
protected_frames_bytes == nullptr ||
protected_frames_bytes_size == nullptr || unprotected_bytes == nullptr ||
unprotected_bytes_size == nullptr) {
return TSI_INVALID_ARGUMENT;
}
if (self->vtable->unprotect == nullptr) return TSI_UNIMPLEMENTED;
return self->vtable->unprotect(self, protected_frames_bytes,
protected_frames_bytes_size, unprotected_bytes,
unprotected_bytes_size);
}
void tsi_frame_protector_destroy(tsi_frame_protector* self) {
if (self == nullptr) return;
self->vtable->destroy(self);
}
/* --- tsi_handshaker common implementation. ---
Calls specific implementation after state/input validation. */
tsi_result tsi_handshaker_get_bytes_to_send_to_peer(tsi_handshaker* self,
unsigned char* bytes,
size_t* bytes_size) {
if (self == nullptr || self->vtable == nullptr || bytes == nullptr ||
bytes_size == nullptr) {
return TSI_INVALID_ARGUMENT;
}
if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
if (self->vtable->get_bytes_to_send_to_peer == nullptr)
return TSI_UNIMPLEMENTED;
return self->vtable->get_bytes_to_send_to_peer(self, bytes, bytes_size);
}
tsi_result tsi_handshaker_process_bytes_from_peer(tsi_handshaker* self,
const unsigned char* bytes,
size_t* bytes_size) {
if (self == nullptr || self->vtable == nullptr || bytes == nullptr ||
bytes_size == nullptr) {
return TSI_INVALID_ARGUMENT;
}
if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
if (self->vtable->process_bytes_from_peer == nullptr)
return TSI_UNIMPLEMENTED;
return self->vtable->process_bytes_from_peer(self, bytes, bytes_size);
}
tsi_result tsi_handshaker_get_result(tsi_handshaker* self) {
if (self == nullptr || self->vtable == nullptr) return TSI_INVALID_ARGUMENT;
if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
if (self->vtable->get_result == nullptr) return TSI_UNIMPLEMENTED;
return self->vtable->get_result(self);
}
tsi_result tsi_handshaker_extract_peer(tsi_handshaker* self, tsi_peer* peer) {
if (self == nullptr || self->vtable == nullptr || peer == nullptr) {
return TSI_INVALID_ARGUMENT;
}
memset(peer, 0, sizeof(tsi_peer));
if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
if (tsi_handshaker_get_result(self) != TSI_OK) {
return TSI_FAILED_PRECONDITION;
}
if (self->vtable->extract_peer == nullptr) return TSI_UNIMPLEMENTED;
return self->vtable->extract_peer(self, peer);
}
tsi_result tsi_handshaker_create_frame_protector(
tsi_handshaker* self, size_t* max_protected_frame_size,
tsi_frame_protector** protector) {
tsi_result result;
if (self == nullptr || self->vtable == nullptr || protector == nullptr) {
return TSI_INVALID_ARGUMENT;
}
if (self->frame_protector_created) return TSI_FAILED_PRECONDITION;
if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
if (tsi_handshaker_get_result(self) != TSI_OK) return TSI_FAILED_PRECONDITION;
if (self->vtable->create_frame_protector == nullptr) return TSI_UNIMPLEMENTED;
result = self->vtable->create_frame_protector(self, max_protected_frame_size,
protector);
if (result == TSI_OK) {
self->frame_protector_created = true;
}
return result;
}
tsi_result tsi_handshaker_next(
tsi_handshaker* self, const unsigned char* received_bytes,
size_t received_bytes_size, const unsigned char** bytes_to_send,
size_t* bytes_to_send_size, tsi_handshaker_result** handshaker_result,
tsi_handshaker_on_next_done_cb cb, void* user_data) {
if (self == nullptr || self->vtable == nullptr) return TSI_INVALID_ARGUMENT;
if (self->handshaker_result_created) return TSI_FAILED_PRECONDITION;
if (self->handshake_shutdown) return TSI_HANDSHAKE_SHUTDOWN;
if (self->vtable->next == nullptr) return TSI_UNIMPLEMENTED;
return self->vtable->next(self, received_bytes, received_bytes_size,
bytes_to_send, bytes_to_send_size,
handshaker_result, cb, user_data);
}
void tsi_handshaker_shutdown(tsi_handshaker* self) {
if (self == nullptr || self->vtable == nullptr) return;
self->handshake_shutdown = true;
if (self->vtable->shutdown != nullptr) {
self->vtable->shutdown(self);
}
}
void tsi_handshaker_destroy(tsi_handshaker* self) {
if (self == nullptr) return;
self->vtable->destroy(self);
}
/* --- tsi_handshaker_result implementation. --- */
tsi_result tsi_handshaker_result_extract_peer(const tsi_handshaker_result* self,
tsi_peer* peer) {
if (self == nullptr || self->vtable == nullptr || peer == nullptr) {
return TSI_INVALID_ARGUMENT;
}
memset(peer, 0, sizeof(tsi_peer));
if (self->vtable->extract_peer == nullptr) return TSI_UNIMPLEMENTED;
return self->vtable->extract_peer(self, peer);
}
tsi_result tsi_handshaker_result_create_frame_protector(
const tsi_handshaker_result* self, size_t* max_protected_frame_size,
tsi_frame_protector** protector) {
if (self == nullptr || self->vtable == nullptr || protector == nullptr) {
return TSI_INVALID_ARGUMENT;
}
if (self->vtable->create_frame_protector == nullptr) return TSI_UNIMPLEMENTED;
return self->vtable->create_frame_protector(self, max_protected_frame_size,
protector);
}
tsi_result tsi_handshaker_result_get_unused_bytes(
const tsi_handshaker_result* self, const unsigned char** bytes,
size_t* bytes_size) {
if (self == nullptr || self->vtable == nullptr || bytes == nullptr ||
bytes_size == nullptr) {
return TSI_INVALID_ARGUMENT;
}
if (self->vtable->get_unused_bytes == nullptr) return TSI_UNIMPLEMENTED;
return self->vtable->get_unused_bytes(self, bytes, bytes_size);
}
void tsi_handshaker_result_destroy(tsi_handshaker_result* self) {
if (self == nullptr) return;
self->vtable->destroy(self);
}
/* --- tsi_peer implementation. --- */
tsi_peer_property tsi_init_peer_property(void) {
tsi_peer_property property;
memset(&property, 0, sizeof(tsi_peer_property));
return property;
}
static void tsi_peer_destroy_list_property(tsi_peer_property* children,
size_t child_count) {
size_t i;
for (i = 0; i < child_count; i++) {
tsi_peer_property_destruct(&children[i]);
}
gpr_free(children);
}
void tsi_peer_property_destruct(tsi_peer_property* property) {
if (property->name != nullptr) {
gpr_free(property->name);
}
if (property->value.data != nullptr) {
gpr_free(property->value.data);
}
*property = tsi_init_peer_property(); /* Reset everything to 0. */
}
void tsi_peer_destruct(tsi_peer* self) {
if (self == nullptr) return;
if (self->properties != nullptr) {
tsi_peer_destroy_list_property(self->properties, self->property_count);
self->properties = nullptr;
}
self->property_count = 0;
}
tsi_result tsi_construct_allocated_string_peer_property(
const char* name, size_t value_length, tsi_peer_property* property) {
*property = tsi_init_peer_property();
if (name != nullptr) property->name = gpr_strdup(name);
if (value_length > 0) {
property->value.data = static_cast<char*>(gpr_zalloc(value_length));
property->value.length = value_length;
}
return TSI_OK;
}
tsi_result tsi_construct_string_peer_property_from_cstring(
const char* name, const char* value, tsi_peer_property* property) {
return tsi_construct_string_peer_property(name, value, strlen(value),
property);
}
tsi_result tsi_construct_string_peer_property(const char* name,
const char* value,
size_t value_length,
tsi_peer_property* property) {
tsi_result result = tsi_construct_allocated_string_peer_property(
name, value_length, property);
if (result != TSI_OK) return result;
if (value_length > 0) {
memcpy(property->value.data, value, value_length);
}
return TSI_OK;
}
tsi_result tsi_construct_peer(size_t property_count, tsi_peer* peer) {
memset(peer, 0, sizeof(tsi_peer));
if (property_count > 0) {
peer->properties = static_cast<tsi_peer_property*>(
gpr_zalloc(property_count * sizeof(tsi_peer_property)));
peer->property_count = property_count;
}
return TSI_OK;
}