Coverage Report

Created: 2026-08-14 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/lib/x509/krb5.c
Line
Count
Source
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) && (streq(princ->data[0], "krbtgt"))) {
113
0
      princ->type = 2; /* KRB_NT_SRV_INST */
114
0
    } else {
115
0
      princ->type = 1; /* KRB_NT_PRINCIPAL */
116
0
    }
117
0
  } else { /* enterprise */
118
0
    princ->data[0] = gnutls_strdup(name);
119
0
    if (princ->data[0] == NULL) {
120
0
      gnutls_assert();
121
0
      goto fail;
122
0
    }
123
124
0
    princ->length++;
125
0
    princ->type = 10; /* KRB_NT_ENTERPRISE */
126
0
  }
127
128
0
  goto cleanup;
129
0
fail:
130
0
  cleanup_principal(princ);
131
0
  princ = NULL;
132
133
0
cleanup:
134
0
  gnutls_free(name);
135
0
  return princ;
136
0
}
137
138
int _gnutls_krb5_principal_to_der(const char *name, gnutls_datum_t *der)
139
0
{
140
0
  int ret, result;
141
0
  asn1_node c2 = NULL;
142
0
  krb5_principal_data *princ;
143
0
  unsigned i;
144
145
0
  princ = name_to_principal(name);
146
0
  if (princ == NULL) {
147
0
    gnutls_assert();
148
0
    ret = GNUTLS_E_PARSING_ERROR;
149
0
    goto cleanup;
150
0
  }
151
152
0
  result = asn1_create_element(_gnutls_get_gnutls_asn(),
153
0
             "GNUTLS.KRB5PrincipalName", &c2);
154
0
  if (result != ASN1_SUCCESS) {
155
0
    gnutls_assert();
156
0
    ret = _gnutls_asn2err(result);
157
0
    goto cleanup;
158
0
  }
159
160
0
  result = asn1_write_value(c2, "realm", princ->realm,
161
0
          strlen(princ->realm));
162
0
  if (result != ASN1_SUCCESS) {
163
0
    gnutls_assert();
164
0
    ret = _gnutls_asn2err(result);
165
0
    goto cleanup;
166
0
  }
167
168
0
  result = asn1_write_value(c2, "principalName.name-type", &princ->type,
169
0
          1);
170
0
  if (result != ASN1_SUCCESS) {
171
0
    gnutls_assert();
172
0
    ret = _gnutls_asn2err(result);
173
0
    goto cleanup;
174
0
  }
175
176
0
  for (i = 0; i < princ->length; i++) {
177
0
    result = asn1_write_value(c2, "principalName.name-string",
178
0
            "NEW", 1);
179
0
    if (result != ASN1_SUCCESS) {
180
0
      gnutls_assert();
181
0
      ret = _gnutls_asn2err(result);
182
0
      goto cleanup;
183
0
    }
184
185
0
    result = asn1_write_value(c2, "principalName.name-string.?LAST",
186
0
            princ->data[i],
187
0
            strlen(princ->data[i]));
188
0
    if (result != ASN1_SUCCESS) {
189
0
      gnutls_assert();
190
0
      ret = _gnutls_asn2err(result);
191
0
      goto cleanup;
192
0
    }
193
0
  }
194
195
0
  ret = _gnutls_x509_der_encode(c2, "", der, 0);
196
0
  if (ret < 0) {
197
0
    gnutls_assert();
198
0
    goto cleanup;
199
0
  }
200
201
0
  ret = 0;
202
0
cleanup:
203
0
  cleanup_principal(princ);
204
0
  asn1_delete_structure(&c2);
205
0
  return ret;
206
0
}
207
208
static int principal_to_str(asn1_node c2, gnutls_buffer_st *str)
209
0
{
210
0
  gnutls_datum_t realm = { NULL, 0 };
211
0
  gnutls_datum_t component = { NULL, 0 };
212
0
  unsigned char name_type[2];
213
0
  int ret, result, len;
214
0
  unsigned i;
215
0
  char val[128];
216
217
0
  ret = _gnutls_x509_read_value(c2, "realm", &realm);
218
0
  if (ret < 0) {
219
0
    gnutls_assert();
220
0
    return ret;
221
0
  }
222
223
0
  len = sizeof(name_type);
224
0
  result =
225
0
    asn1_read_value(c2, "principalName.name-type", name_type, &len);
226
0
  if (result != ASN1_SUCCESS) {
227
0
    gnutls_assert();
228
0
    ret = _gnutls_asn2err(result);
229
0
    goto cleanup;
230
0
  }
231
232
0
  if (len != 1 ||
233
0
      (name_type[0] != 1 && name_type[0] != 2 && name_type[0] != 10)) {
234
0
    ret = GNUTLS_E_INVALID_REQUEST;
235
0
    goto cleanup;
236
0
  }
237
238
0
  for (i = 0;; i++) {
239
0
    snprintf(val, sizeof(val), "principalName.name-string.?%u",
240
0
       i + 1);
241
0
    ret = _gnutls_x509_read_value(c2, val, &component);
242
0
    if (ret == GNUTLS_E_ASN1_VALUE_NOT_FOUND ||
243
0
        ret == GNUTLS_E_ASN1_ELEMENT_NOT_FOUND)
244
0
      break;
245
0
    if (ret < 0) {
246
0
      gnutls_assert();
247
0
      goto cleanup;
248
0
    }
249
250
0
    if (i > 0) {
251
0
      ret = _gnutls_buffer_append_data(str, "/", 1);
252
0
      if (ret < 0) {
253
0
        gnutls_assert();
254
0
        goto cleanup;
255
0
      }
256
0
    }
257
258
0
    ret = _gnutls_buffer_append_data(str, component.data,
259
0
             component.size);
260
0
    if (ret < 0) {
261
0
      gnutls_assert();
262
0
      goto cleanup;
263
0
    }
264
265
0
    _gnutls_free_datum(&component);
266
0
  }
267
268
0
  ret = _gnutls_buffer_append_data(str, "@", 1);
269
0
  if (ret < 0) {
270
0
    gnutls_assert();
271
0
    goto cleanup;
272
0
  }
273
274
0
  ret = _gnutls_buffer_append_data(str, realm.data, realm.size);
275
0
  if (ret < 0) {
276
0
    gnutls_assert();
277
0
    goto cleanup;
278
0
  }
279
280
0
  ret = 0;
281
0
cleanup:
282
0
  _gnutls_free_datum(&component);
283
0
  gnutls_free(realm.data);
284
0
  return ret;
285
0
}
286
287
int _gnutls_krb5_der_to_principal(const gnutls_datum_t *der,
288
          gnutls_datum_t *name)
289
0
{
290
0
  int ret, result;
291
0
  asn1_node c2 = NULL;
292
0
  gnutls_buffer_st str;
293
294
0
  _gnutls_buffer_init(&str);
295
296
0
  result = asn1_create_element(_gnutls_get_gnutls_asn(),
297
0
             "GNUTLS.KRB5PrincipalName", &c2);
298
0
  if (result != ASN1_SUCCESS) {
299
0
    gnutls_assert();
300
0
    ret = _gnutls_asn2err(result);
301
0
    goto cleanup;
302
0
  }
303
304
0
  result = asn1_der_decoding(&c2, der->data, der->size, NULL);
305
0
  if (result != ASN1_SUCCESS) {
306
0
    gnutls_assert();
307
0
    ret = _gnutls_asn2err(result);
308
0
    goto cleanup;
309
0
  }
310
311
0
  ret = principal_to_str(c2, &str);
312
0
  if (ret < 0) {
313
    /* for some reason we cannot convert to a human readable string
314
     * the principal. Then we use the #HEX format.
315
     */
316
0
    _gnutls_buffer_reset(&str);
317
0
    ret = _gnutls_buffer_append_data(&str, "#", 1);
318
0
    if (ret < 0) {
319
0
      gnutls_assert();
320
0
      goto cleanup;
321
0
    }
322
323
0
    _gnutls_buffer_hexprint(&str, der->data, der->size);
324
0
  }
325
326
0
  asn1_delete_structure(&c2);
327
0
  return _gnutls_buffer_to_datum(&str, name, 1);
328
329
0
cleanup:
330
0
  _gnutls_buffer_clear(&str);
331
0
  asn1_delete_structure(&c2);
332
0
  return ret;
333
0
}