Coverage Report

Created: 2023-03-26 07:33

/src/gnutls/lib/x509/krb5.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (C) 2015 Red Hat, Inc.
3
 *
4
 * Author: Nikos Mavrogiannopoulos
5
 *
6
 * This file is part of GnuTLS.
7
 *
8
 * The GnuTLS is free software; you can redistribute it and/or
9
 * modify it under the terms of the GNU Lesser General Public License
10
 * as published by the Free Software Foundation; either version 2.1 of
11
 * the License, or (at your option) any later version.
12
 *
13
 * This library is distributed in the hope that it will be useful, but
14
 * WITHOUT ANY WARRANTY; without even the implied warranty of
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16
 * Lesser General Public License for more details.
17
 *
18
 * You should have received a copy of the GNU Lesser General Public License
19
 * along with this program.  If not, see <https://www.gnu.org/licenses/>
20
 *
21
 */
22
23
#include <config.h>
24
#include <gnutls/gnutls.h>
25
#include <libtasn1.h>
26
#include <string.h>
27
#include <stdint.h>
28
#include <stdlib.h>
29
#include <errors.h>
30
#include "krb5.h"
31
#include "common.h"
32
33
0
#define _gnutls_asn2err(x) GNUTLS_E_ASN1_DER_ERROR
34
35
0
#define MAX_COMPONENTS 6
36
37
typedef struct krb5_principal_data {
38
  char *realm;
39
  char *data[MAX_COMPONENTS];
40
  uint32_t length;
41
  int8_t type;
42
} krb5_principal_data;
43
44
extern const asn1_static_node krb5_asn1_tab[];
45
46
static void cleanup_principal(krb5_principal_data * princ)
47
0
{
48
0
  unsigned i;
49
0
  if (princ) {
50
0
    gnutls_free(princ->realm);
51
0
    for (i = 0; i < princ->length; i++)
52
0
      gnutls_free(princ->data[i]);
53
0
    memset(princ, 0, sizeof(*princ));
54
0
    gnutls_free(princ);
55
0
  }
56
0
}
57
58
static krb5_principal_data *name_to_principal(const char *_name)
59
0
{
60
0
  krb5_principal_data *princ;
61
0
  char *p, *p2, *sp;
62
0
  unsigned pos = 0;
63
0
  char *name = NULL;
64
65
0
  princ = gnutls_calloc(1, sizeof(struct krb5_principal_data));
66
0
  if (princ == NULL)
67
0
    return NULL;
68
69
0
  name = gnutls_strdup(_name);
70
0
  if (name == NULL) {
71
0
    gnutls_assert();
72
0
    goto fail;
73
0
  }
74
75
0
  p = strrchr(name, '@');
76
0
  p2 = strchr(name, '@');
77
0
  if (p == NULL) {
78
    /* unknown name type */
79
0
    gnutls_assert();
80
0
    goto fail;
81
0
  }
82
83
0
  princ->realm = gnutls_strdup(p + 1);
84
0
  if (princ->realm == NULL) {
85
0
    gnutls_assert();
86
0
    goto fail;
87
0
  }
88
0
  *p = 0;
89
90
0
  if (p == p2) {
91
0
    p = strtok_r(name, "/", &sp);
92
0
    while (p) {
93
0
      if (pos == MAX_COMPONENTS) {
94
0
        _gnutls_debug_log
95
0
            ("%s: Cannot parse names with more than %d components\n",
96
0
             __func__, MAX_COMPONENTS);
97
0
        goto fail;
98
0
      }
99
100
0
      princ->data[pos] = gnutls_strdup(p);
101
0
      if (princ->data[pos] == NULL) {
102
0
        gnutls_assert();
103
0
        goto fail;
104
0
      }
105
106
0
      princ->length++;
107
0
      pos++;
108
109
0
      p = strtok_r(NULL, "/", &sp);
110
0
    }
111
112
0
    if ((princ->length == 2)
113
0
        && (strcmp(princ->data[0], "krbtgt") == 0)) {
114
0
      princ->type = 2;  /* KRB_NT_SRV_INST */
115
0
    } else {
116
0
      princ->type = 1;  /* KRB_NT_PRINCIPAL */
117
0
    }
118
0
  } else {   /* enterprise */
119
0
    princ->data[0] = gnutls_strdup(name);
120
0
    if (princ->data[0] == NULL) {
121
0
      gnutls_assert();
122
0
      goto fail;
123
0
    }
124
125
0
    princ->length++;
126
0
    princ->type = 10; /* KRB_NT_ENTERPRISE */
127
0
  }
128
129
0
  goto cleanup;
130
0
 fail:
131
0
  cleanup_principal(princ);
132
0
  princ = NULL;
133
134
0
 cleanup:
135
0
  gnutls_free(name);
136
0
  return princ;
137
0
}
138
139
int _gnutls_krb5_principal_to_der(const char *name, gnutls_datum_t * der)
140
0
{
141
0
  int ret, result;
142
0
  asn1_node c2 = NULL;
143
0
  krb5_principal_data *princ;
144
0
  unsigned i;
145
146
0
  princ = name_to_principal(name);
147
0
  if (princ == NULL) {
148
0
    gnutls_assert();
149
0
    ret = GNUTLS_E_PARSING_ERROR;
150
0
    goto cleanup;
151
0
  }
152
153
0
  result =
154
0
      asn1_create_element(_gnutls_get_gnutls_asn(),
155
0
        "GNUTLS.KRB5PrincipalName", &c2);
156
0
  if (result != ASN1_SUCCESS) {
157
0
    gnutls_assert();
158
0
    ret = _gnutls_asn2err(result);
159
0
    goto cleanup;
160
0
  }
161
162
0
  result =
163
0
      asn1_write_value(c2, "realm", princ->realm, strlen(princ->realm));
164
0
  if (result != ASN1_SUCCESS) {
165
0
    gnutls_assert();
166
0
    ret = _gnutls_asn2err(result);
167
0
    goto cleanup;
168
0
  }
169
170
0
  result =
171
0
      asn1_write_value(c2, "principalName.name-type", &princ->type, 1);
172
0
  if (result != ASN1_SUCCESS) {
173
0
    gnutls_assert();
174
0
    ret = _gnutls_asn2err(result);
175
0
    goto cleanup;
176
0
  }
177
178
0
  for (i = 0; i < princ->length; i++) {
179
0
    result =
180
0
        asn1_write_value(c2, "principalName.name-string", "NEW", 1);
181
0
    if (result != ASN1_SUCCESS) {
182
0
      gnutls_assert();
183
0
      ret = _gnutls_asn2err(result);
184
0
      goto cleanup;
185
0
    }
186
187
0
    result =
188
0
        asn1_write_value(c2,
189
0
             "principalName.name-string.?LAST",
190
0
             princ->data[i], strlen(princ->data[i]));
191
0
    if (result != ASN1_SUCCESS) {
192
0
      gnutls_assert();
193
0
      ret = _gnutls_asn2err(result);
194
0
      goto cleanup;
195
0
    }
196
0
  }
197
198
0
  ret = _gnutls_x509_der_encode(c2, "", der, 0);
199
0
  if (ret < 0) {
200
0
    gnutls_assert();
201
0
    goto cleanup;
202
0
  }
203
204
0
  ret = 0;
205
0
 cleanup:
206
0
  cleanup_principal(princ);
207
0
  asn1_delete_structure(&c2);
208
0
  return ret;
209
0
}
210
211
static int principal_to_str(asn1_node c2, gnutls_buffer_st * str)
212
0
{
213
0
  gnutls_datum_t realm = { NULL, 0 };
214
0
  gnutls_datum_t component = { NULL, 0 };
215
0
  unsigned char name_type[2];
216
0
  int ret, result, len;
217
0
  unsigned i;
218
0
  char val[128];
219
220
0
  ret = _gnutls_x509_read_value(c2, "realm", &realm);
221
0
  if (ret < 0) {
222
0
    gnutls_assert();
223
0
    return ret;
224
0
  }
225
226
0
  len = sizeof(name_type);
227
0
  result =
228
0
      asn1_read_value(c2, "principalName.name-type", name_type, &len);
229
0
  if (result != ASN1_SUCCESS) {
230
0
    gnutls_assert();
231
0
    ret = _gnutls_asn2err(result);
232
0
    goto cleanup;
233
0
  }
234
235
0
  if (len != 1
236
0
      || (name_type[0] != 1 && name_type[0] != 2 && name_type[0] != 10)) {
237
0
    ret = GNUTLS_E_INVALID_REQUEST;
238
0
    goto cleanup;
239
0
  }
240
241
0
  for (i = 0;; i++) {
242
0
    snprintf(val, sizeof(val), "principalName.name-string.?%u",
243
0
       i + 1);
244
0
    ret = _gnutls_x509_read_value(c2, val, &component);
245
0
    if (ret == GNUTLS_E_ASN1_VALUE_NOT_FOUND
246
0
        || ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
247
0
      break;
248
0
    if (ret < 0) {
249
0
      gnutls_assert();
250
0
      goto cleanup;
251
0
    }
252
253
0
    if (i > 0) {
254
0
      ret = _gnutls_buffer_append_data(str, "/", 1);
255
0
      if (ret < 0) {
256
0
        gnutls_assert();
257
0
        goto cleanup;
258
0
      }
259
0
    }
260
261
0
    ret =
262
0
        _gnutls_buffer_append_data(str, component.data,
263
0
                 component.size);
264
0
    if (ret < 0) {
265
0
      gnutls_assert();
266
0
      goto cleanup;
267
0
    }
268
269
0
    _gnutls_free_datum(&component);
270
0
  }
271
272
0
  ret = _gnutls_buffer_append_data(str, "@", 1);
273
0
  if (ret < 0) {
274
0
    gnutls_assert();
275
0
    goto cleanup;
276
0
  }
277
278
0
  ret = _gnutls_buffer_append_data(str, realm.data, realm.size);
279
0
  if (ret < 0) {
280
0
    gnutls_assert();
281
0
    goto cleanup;
282
0
  }
283
284
0
  ret = 0;
285
0
 cleanup:
286
0
  _gnutls_free_datum(&component);
287
0
  gnutls_free(realm.data);
288
0
  return ret;
289
0
}
290
291
int _gnutls_krb5_der_to_principal(const gnutls_datum_t * der,
292
          gnutls_datum_t * name)
293
0
{
294
0
  int ret, result;
295
0
  asn1_node c2 = NULL;
296
0
  gnutls_buffer_st str;
297
298
0
  _gnutls_buffer_init(&str);
299
300
0
  result =
301
0
      asn1_create_element(_gnutls_get_gnutls_asn(),
302
0
        "GNUTLS.KRB5PrincipalName", &c2);
303
0
  if (result != ASN1_SUCCESS) {
304
0
    gnutls_assert();
305
0
    ret = _gnutls_asn2err(result);
306
0
    goto cleanup;
307
0
  }
308
309
0
  result = asn1_der_decoding(&c2, der->data, der->size, NULL);
310
0
  if (result != ASN1_SUCCESS) {
311
0
    gnutls_assert();
312
0
    ret = _gnutls_asn2err(result);
313
0
    goto cleanup;
314
0
  }
315
316
0
  ret = principal_to_str(c2, &str);
317
0
  if (ret < 0) {
318
    /* for some reason we cannot convert to a human readable string
319
     * the principal. Then we use the #HEX format.
320
     */
321
0
    _gnutls_buffer_reset(&str);
322
0
    ret = _gnutls_buffer_append_data(&str, "#", 1);
323
0
    if (ret < 0) {
324
0
      gnutls_assert();
325
0
      goto cleanup;
326
0
    }
327
328
0
    _gnutls_buffer_hexprint(&str, der->data, der->size);
329
0
  }
330
331
0
  asn1_delete_structure(&c2);
332
0
  return _gnutls_buffer_to_datum(&str, name, 1);
333
334
0
 cleanup:
335
0
  _gnutls_buffer_clear(&str);
336
0
  asn1_delete_structure(&c2);
337
0
  return ret;
338
0
}