aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.cc
blob: 7ba03eb7f0bf218b4fac466fd3b29fee6cba8937 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/*
 *
 * Copyright 2018 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/alts/zero_copy_frame_protector/alts_grpc_integrity_only_record_protocol.h"

#include <grpc/support/alloc.h>
#include <grpc/support/log.h>

#include "src/core/lib/slice/slice_internal.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_grpc_record_protocol_common.h"
#include "src/core/tsi/alts/zero_copy_frame_protector/alts_iovec_record_protocol.h"

/* Main struct for alts_grpc_integrity_only_record_protocol.  */
typedef struct alts_grpc_integrity_only_record_protocol {
  alts_grpc_record_protocol base;
  grpc_slice_buffer data_sb;
  unsigned char* tag_buf;
} alts_grpc_integrity_only_record_protocol;

/* --- alts_grpc_record_protocol methods implementation. --- */

static tsi_result alts_grpc_integrity_only_protect(
    alts_grpc_record_protocol* rp, grpc_slice_buffer* unprotected_slices,
    grpc_slice_buffer* protected_slices) {
  /* Input sanity check.  */
  if (rp == nullptr || unprotected_slices == nullptr ||
      protected_slices == nullptr) {
    gpr_log(GPR_ERROR,
            "Invalid nullptr arguments to alts_grpc_record_protocol protect.");
    return TSI_INVALID_ARGUMENT;
  }
  /* Allocates memory for header and tag slices.  */
  grpc_slice header_slice = GRPC_SLICE_MALLOC(rp->header_length);
  grpc_slice tag_slice = GRPC_SLICE_MALLOC(rp->tag_length);
  /* Calls alts_iovec_record_protocol protect.  */
  char* error_details = nullptr;
  iovec_t header_iovec = {GRPC_SLICE_START_PTR(header_slice),
                          GRPC_SLICE_LENGTH(header_slice)};
  iovec_t tag_iovec = {GRPC_SLICE_START_PTR(tag_slice),
                       GRPC_SLICE_LENGTH(tag_slice)};
  alts_grpc_record_protocol_convert_slice_buffer_to_iovec(rp,
                                                          unprotected_slices);
  grpc_status_code status = alts_iovec_record_protocol_integrity_only_protect(
      rp->iovec_rp, rp->iovec_buf, unprotected_slices->count, header_iovec,
      tag_iovec, &error_details);
  if (status != GRPC_STATUS_OK) {
    gpr_log(GPR_ERROR, "Failed to protect, %s", error_details);
    gpr_free(error_details);
    return TSI_INTERNAL_ERROR;
  }
  /* Appends result to protected_slices.  */
  grpc_slice_buffer_add(protected_slices, header_slice);
  grpc_slice_buffer_move_into(unprotected_slices, protected_slices);
  grpc_slice_buffer_add(protected_slices, tag_slice);
  return TSI_OK;
}

static tsi_result alts_grpc_integrity_only_unprotect(
    alts_grpc_record_protocol* rp, grpc_slice_buffer* protected_slices,
    grpc_slice_buffer* unprotected_slices) {
  /* Input sanity check.  */
  if (rp == nullptr || protected_slices == nullptr ||
      unprotected_slices == nullptr) {
    gpr_log(
        GPR_ERROR,
        "Invalid nullptr arguments to alts_grpc_record_protocol unprotect.");
    return TSI_INVALID_ARGUMENT;
  }
  if (protected_slices->length < rp->header_length + rp->tag_length) {
    gpr_log(GPR_ERROR, "Protected slices do not have sufficient data.");
    return TSI_INVALID_ARGUMENT;
  }
  /* In this method, rp points to alts_grpc_record_protocol struct
   * and integrity_only_record_protocol points to
   * alts_grpc_integrity_only_record_protocol struct.  */
  alts_grpc_integrity_only_record_protocol* integrity_only_record_protocol =
      reinterpret_cast<alts_grpc_integrity_only_record_protocol*>(rp);
  /* Strips frame header from protected slices.  */
  grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb);
  grpc_slice_buffer_move_first(protected_slices, rp->header_length,
                               &rp->header_sb);
  GPR_ASSERT(rp->header_sb.length == rp->header_length);
  iovec_t header_iovec = alts_grpc_record_protocol_get_header_iovec(rp);
  /* Moves protected slices data to data_sb and leaves the remaining tag.  */
  grpc_slice_buffer_reset_and_unref_internal(
      &integrity_only_record_protocol->data_sb);
  grpc_slice_buffer_move_first(protected_slices,
                               protected_slices->length - rp->tag_length,
                               &integrity_only_record_protocol->data_sb);
  GPR_ASSERT(protected_slices->length == rp->tag_length);
  iovec_t tag_iovec = {nullptr, rp->tag_length};
  if (protected_slices->count == 1) {
    tag_iovec.iov_base = GRPC_SLICE_START_PTR(protected_slices->slices[0]);
  } else {
    /* Frame tag is in multiple slices, copies the tag bytes from slice
     * buffer to a single flat buffer.  */
    alts_grpc_record_protocol_copy_slice_buffer(
        protected_slices, integrity_only_record_protocol->tag_buf);
    tag_iovec.iov_base = integrity_only_record_protocol->tag_buf;
  }
  /* Calls alts_iovec_record_protocol unprotect.  */
  char* error_details = nullptr;
  alts_grpc_record_protocol_convert_slice_buffer_to_iovec(
      rp, &integrity_only_record_protocol->data_sb);
  grpc_status_code status = alts_iovec_record_protocol_integrity_only_unprotect(
      rp->iovec_rp, rp->iovec_buf,
      integrity_only_record_protocol->data_sb.count, header_iovec, tag_iovec,
      &error_details);
  if (status != GRPC_STATUS_OK) {
    gpr_log(GPR_ERROR, "Failed to unprotect, %s", error_details);
    gpr_free(error_details);
    return TSI_INTERNAL_ERROR;
  }
  grpc_slice_buffer_reset_and_unref_internal(&rp->header_sb);
  grpc_slice_buffer_reset_and_unref_internal(protected_slices);
  grpc_slice_buffer_move_into(&integrity_only_record_protocol->data_sb,
                              unprotected_slices);
  return TSI_OK;
}

static void alts_grpc_integrity_only_destruct(alts_grpc_record_protocol* rp) {
  if (rp == nullptr) {
    return;
  }
  alts_grpc_integrity_only_record_protocol* integrity_only_rp =
      reinterpret_cast<alts_grpc_integrity_only_record_protocol*>(rp);
  grpc_slice_buffer_destroy_internal(&integrity_only_rp->data_sb);
  gpr_free(integrity_only_rp->tag_buf);
}

static const alts_grpc_record_protocol_vtable
    alts_grpc_integrity_only_record_protocol_vtable = {
        alts_grpc_integrity_only_protect, alts_grpc_integrity_only_unprotect,
        alts_grpc_integrity_only_destruct};

tsi_result alts_grpc_integrity_only_record_protocol_create(
    gsec_aead_crypter* crypter, size_t overflow_size, bool is_client,
    bool is_protect, alts_grpc_record_protocol** rp) {
  if (crypter == nullptr || rp == nullptr) {
    gpr_log(GPR_ERROR,
            "Invalid nullptr arguments to alts_grpc_record_protocol create.");
    return TSI_INVALID_ARGUMENT;
  }
  alts_grpc_integrity_only_record_protocol* impl =
      static_cast<alts_grpc_integrity_only_record_protocol*>(
          gpr_zalloc(sizeof(alts_grpc_integrity_only_record_protocol)));
  /* Calls alts_grpc_record_protocol init.  */
  tsi_result result = alts_grpc_record_protocol_init(
      &impl->base, crypter, overflow_size, is_client,
      /*is_integrity_only=*/true, is_protect);
  if (result != TSI_OK) {
    gpr_free(impl);
    return result;
  }
  /* Initializes slice buffer for data_sb.  */
  grpc_slice_buffer_init(&impl->data_sb);
  /* Allocates tag buffer.  */
  impl->tag_buf =
      static_cast<unsigned char*>(gpr_malloc(impl->base.tag_length));
  impl->base.vtable = &alts_grpc_integrity_only_record_protocol_vtable;
  *rp = &impl->base;
  return TSI_OK;
}