Coverage Report

Created: 2024-09-03 06:48

/src/net-snmp/snmplib/cert_util.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Portions of this file are subject to the following copyright(s).  See
3
 * the Net-SNMP's COPYING file for more details and other copyrights
4
 * that may apply:
5
 *
6
 * Portions of this file are copyrighted by:
7
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
8
 * Use is subject to license terms specified in the COPYING file
9
 * distributed with the Net-SNMP package.
10
 */
11
12
#include <net-snmp/net-snmp-config.h>
13
#include <net-snmp/net-snmp-features.h>
14
15
#if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && NETSNMP_TRANSPORT_TLSBASE_DOMAIN
16
netsnmp_feature_child_of(cert_util_all, libnetsnmp);
17
netsnmp_feature_child_of(cert_util, cert_util_all);
18
#ifdef NETSNMP_FEATURE_REQUIRE_CERT_UTIL
19
netsnmp_feature_require(container_directory);
20
netsnmp_feature_require(container_fifo);
21
netsnmp_feature_require(container_dup);
22
netsnmp_feature_require(container_free_all);
23
netsnmp_feature_require(subcontainer_find);
24
25
netsnmp_feature_child_of(cert_map_remove, netsnmp_unused);
26
netsnmp_feature_child_of(cert_map_find, netsnmp_unused);
27
netsnmp_feature_child_of(tlstmparams_external, cert_util_all);
28
netsnmp_feature_child_of(tlstmparams_container, tlstmparams_external);
29
netsnmp_feature_child_of(tlstmparams_remove, tlstmparams_external);
30
netsnmp_feature_child_of(tlstmparams_find, tlstmparams_external);
31
netsnmp_feature_child_of(tlstmAddr_remove, netsnmp_unused);
32
netsnmp_feature_child_of(tlstmaddr_external, cert_util_all);
33
netsnmp_feature_child_of(tlstmaddr_container, tlstmaddr_external);
34
netsnmp_feature_child_of(tlstmAddr_get_serverId, tlstmaddr_external);
35
36
netsnmp_feature_child_of(cert_fingerprints, cert_util_all);
37
netsnmp_feature_child_of(tls_fingerprint_build, cert_util_all);
38
39
#endif /* NETSNMP_FEATURE_REQUIRE_CERT_UTIL */
40
41
#ifndef NETSNMP_FEATURE_REMOVE_CERT_UTIL
42
43
#include <ctype.h>
44
45
#include <stddef.h>
46
47
#ifdef HAVE_STDLIB_H
48
#include <stdlib.h>
49
#endif
50
51
#ifdef HAVE_STRING_H
52
#include <string.h>
53
#else
54
#include <strings.h>
55
#endif
56
57
#ifdef HAVE_SYS_STAT_H
58
#   include <sys/stat.h>
59
#endif
60
#ifdef HAVE_DIRENT_H
61
#include <dirent.h>
62
#endif
63
64
#include <net-snmp/types.h>
65
#include <net-snmp/output_api.h>
66
#include <net-snmp/config_api.h>
67
68
#include <net-snmp/library/snmp.h>
69
#include <net-snmp/library/snmp_assert.h>
70
#include <net-snmp/library/snmp_transport.h>
71
#include <net-snmp/library/system.h>
72
#include <net-snmp/library/tools.h>
73
#include <net-snmp/library/container.h>
74
#include <net-snmp/library/data_list.h>
75
#include <net-snmp/library/file_utils.h>
76
#include <net-snmp/library/dir_utils.h>
77
#include <net-snmp/library/read_config.h>
78
79
#include <openssl/ssl.h>
80
#include <openssl/err.h>
81
#include <openssl/x509v3.h>
82
#include <net-snmp/library/cert_util.h>
83
#include <net-snmp/library/snmp_openssl.h>
84
85
#ifndef NAME_MAX
86
#define NAME_MAX 255
87
#endif
88
89
/*
90
 * bump this value whenever cert index format changes, so indexes
91
 * will be regenerated with new format.
92
 */
93
0
#define CERT_INDEX_FORMAT  2
94
95
static netsnmp_container *_certs = NULL;
96
static netsnmp_container *_keys = NULL;
97
static netsnmp_container *_maps = NULL;
98
static netsnmp_container *_tlstmParams = NULL;
99
static netsnmp_container *_tlstmAddr = NULL;
100
static struct snmp_enum_list *_certindexes = NULL;
101
102
static netsnmp_container *_trusted_certs = NULL;
103
104
static void _setup_containers(void);
105
106
static void _cert_indexes_load(void);
107
static void _cert_free(void *cert, void *context);
108
static void _key_free(void *key, void *context);
109
static int  _cert_compare(const void *p, const void *q);
110
static int  _cert_sn_compare(const void *p, const void *q);
111
static int  _cert_sn_ncompare(const void *p, const void *q);
112
static int  _cert_cn_compare(const void *p, const void *q);
113
static int  _cert_fn_compare(const void *p, const void *q);
114
static int  _cert_fn_ncompare(const void *p, const void *q);
115
static void _find_partner(netsnmp_cert *cert, netsnmp_key *key);
116
static netsnmp_cert *_find_issuer(netsnmp_cert *cert);
117
static netsnmp_void_array *_cert_reduce_subset_first(netsnmp_void_array *matching);
118
static netsnmp_void_array *_cert_reduce_subset_what(netsnmp_void_array *matching, int what);
119
static netsnmp_void_array *_cert_find_subset_fn(const char *filename,
120
                                                const char *directory);
121
static netsnmp_void_array *_cert_find_subset_sn(const char *subject);
122
static netsnmp_void_array *_key_find_subset(const char *filename);
123
static netsnmp_cert *_cert_find_fp(const char *fingerprint);
124
static char *_find_tlstmParams_fingerprint(const char *param);
125
static char *_find_tlstmAddr_fingerprint(const char *name);
126
static const char *_mode_str(u_char mode);
127
static const char *_where_str(u_int what);
128
void netsnmp_cert_dump_all(void);
129
130
int netsnmp_cert_load_x509(netsnmp_cert *cert);
131
132
void netsnmp_cert_free(netsnmp_cert *cert);
133
void netsnmp_key_free(netsnmp_key *key);
134
135
static int _certindex_add( const char *dirname, int i );
136
137
static int _time_filter(const void *text, void *ctx);
138
139
static void _init_tlstmCertToTSN(void);
140
5.60k
#define TRUSTCERT_CONFIG_TOKEN "trustCert"
141
static void _parse_trustcert(const char *token, char *line);
142
143
static void _init_tlstmParams(void);
144
static void _init_tlstmAddr(void);
145
146
/** mode descriptions should match up with header */
147
static const char _modes[][256] =
148
        {
149
            "none",
150
            "identity",
151
            "remote_peer",
152
            "identity+remote_peer",
153
            "reserved1",
154
            "reserved1+identity",
155
            "reserved1+remote_peer",
156
            "reserved1+identity+remote_peer",
157
            "CA",
158
            "CA+identity",
159
            "CA+remote_peer",
160
            "CA+identity+remote_peer",
161
            "CA+reserved1",
162
            "CA+reserved1+identity",
163
            "CA+reserved1+remote_peer",
164
            "CA+reserved1+identity+remote_peer",
165
        };
166
167
/* #####################################################################
168
 *
169
 * init and shutdown functions
170
 *
171
 */
172
173
void
174
_netsnmp_release_trustcerts(void)
175
11.1k
{
176
11.1k
    if (NULL != _trusted_certs) {
177
2.80k
        CONTAINER_FREE_ALL(_trusted_certs, NULL);
178
2.80k
        CONTAINER_FREE(_trusted_certs);
179
2.80k
        _trusted_certs = NULL;
180
2.80k
    }
181
11.1k
}
182
183
void
184
_setup_trusted_certs(void)
185
2.80k
{
186
2.80k
    _trusted_certs = netsnmp_container_find("trusted_certs:fifo");
187
2.80k
    if (NULL == _trusted_certs) {
188
0
        snmp_log(LOG_ERR, "could not create container for trusted certs\n");
189
0
        netsnmp_certs_shutdown();
190
0
        return;
191
0
    }
192
2.80k
    _trusted_certs->container_name = strdup("trusted certificates");
193
2.80k
    _trusted_certs->compare = netsnmp_str_compare;
194
2.80k
}
195
196
/*
197
 * secname mapping for servers.
198
 */
199
void
200
netsnmp_certs_agent_init(void)
201
2.79k
{
202
2.79k
    _init_tlstmCertToTSN();
203
2.79k
    _init_tlstmParams();
204
2.79k
    _init_tlstmAddr();
205
2.79k
}
206
207
void
208
netsnmp_certs_init(void)
209
2.80k
{
210
2.80k
    const char *trustCert_help = TRUSTCERT_CONFIG_TOKEN
211
2.80k
        " FINGERPRINT|FILENAME";
212
213
2.80k
    register_config_handler("snmp", TRUSTCERT_CONFIG_TOKEN,
214
2.80k
                            _parse_trustcert, _netsnmp_release_trustcerts,
215
2.80k
                            trustCert_help);
216
2.80k
    _setup_containers();
217
218
    /** add certificate type mapping */
219
2.80k
    se_add_pair_to_slist("cert_types", strdup("pem"), NS_CERT_TYPE_PEM);
220
2.80k
    se_add_pair_to_slist("cert_types", strdup("crt"), NS_CERT_TYPE_DER);
221
2.80k
    se_add_pair_to_slist("cert_types", strdup("cer"), NS_CERT_TYPE_DER);
222
2.80k
    se_add_pair_to_slist("cert_types", strdup("cert"), NS_CERT_TYPE_DER);
223
2.80k
    se_add_pair_to_slist("cert_types", strdup("der"), NS_CERT_TYPE_DER);
224
2.80k
    se_add_pair_to_slist("cert_types", strdup("key"), NS_CERT_TYPE_KEY);
225
2.80k
    se_add_pair_to_slist("cert_types", strdup("private"), NS_CERT_TYPE_KEY);
226
227
    /** hash algs */
228
2.80k
    se_add_pair_to_slist("cert_hash_alg", strdup("sha1"), NS_HASH_SHA1);
229
2.80k
    se_add_pair_to_slist("cert_hash_alg", strdup("md5"), NS_HASH_MD5);
230
2.80k
    se_add_pair_to_slist("cert_hash_alg", strdup("sha224"), NS_HASH_SHA224);
231
2.80k
    se_add_pair_to_slist("cert_hash_alg", strdup("sha256"), NS_HASH_SHA256);
232
2.80k
    se_add_pair_to_slist("cert_hash_alg", strdup("sha384"), NS_HASH_SHA384);
233
2.80k
    se_add_pair_to_slist("cert_hash_alg", strdup("sha512"), NS_HASH_SHA512);
234
235
    /** map types */
236
2.80k
    se_add_pair_to_slist("cert_map_type", strdup("cn"),
237
2.80k
                         TSNM_tlstmCertCommonName);
238
2.80k
    se_add_pair_to_slist("cert_map_type", strdup("ip"),
239
2.80k
                         TSNM_tlstmCertSANIpAddress);
240
2.80k
    se_add_pair_to_slist("cert_map_type", strdup("rfc822"),
241
2.80k
                         TSNM_tlstmCertSANRFC822Name);
242
2.80k
    se_add_pair_to_slist("cert_map_type", strdup("dns"),
243
2.80k
                         TSNM_tlstmCertSANDNSName);
244
2.80k
    se_add_pair_to_slist("cert_map_type", strdup("any"), TSNM_tlstmCertSANAny);
245
2.80k
    se_add_pair_to_slist("cert_map_type", strdup("sn"),
246
2.80k
                         TSNM_tlstmCertSpecified);
247
248
2.80k
}
249
250
void
251
netsnmp_certs_shutdown(void)
252
5.59k
{
253
5.59k
    DEBUGMSGT(("cert:util:shutdown","shutdown\n"));
254
5.59k
    netsnmp_container ***c, **containers[] = {
255
5.59k
        &_tlstmParams, &_tlstmAddr, &_maps, &_certs, &_keys, NULL
256
5.59k
    };
257
258
33.5k
    for (c = containers; *c; c++) {
259
27.9k
        if (!**c)
260
13.9k
            continue;
261
13.9k
        CONTAINER_FREE_ALL(**c, NULL);
262
13.9k
        CONTAINER_FREE(**c);
263
13.9k
        **c = NULL;
264
13.9k
    }
265
5.59k
    _netsnmp_release_trustcerts();
266
5.59k
}
267
268
void
269
netsnmp_certs_load(void)
270
2
{
271
2
    netsnmp_iterator  *itr;
272
2
    netsnmp_key        *key;
273
2
    netsnmp_cert       *cert;
274
275
2
    DEBUGMSGT(("cert:util:init","init\n"));
276
277
2
    if (NULL == _certs) {
278
0
        snmp_log(LOG_ERR, "cant load certs without container\n");
279
0
        return;
280
0
    }
281
282
2
    if (CONTAINER_SIZE(_certs) != 0) {
283
0
        DEBUGMSGT(("cert:util:init", "ignoring duplicate init\n"));
284
0
        return;
285
0
    }
286
287
2
    netsnmp_init_openssl();
288
289
    /** scan config dirs for certs */
290
2
    _cert_indexes_load();
291
292
    /** match up keys w/certs */
293
2
    itr = CONTAINER_ITERATOR(_keys);
294
2
    if (NULL == itr) {
295
0
        snmp_log(LOG_ERR, "could not get iterator for keys\n");
296
0
        netsnmp_certs_shutdown();
297
0
        return;
298
0
    }
299
2
    key = ITERATOR_FIRST(itr);
300
2
    for( ; key; key = ITERATOR_NEXT(itr))
301
0
        _find_partner(NULL, key);
302
2
    ITERATOR_RELEASE(itr);
303
304
2
    DEBUGIF("cert:dump") {
305
1
        itr = CONTAINER_ITERATOR(_certs);
306
1
        if (NULL == itr) {
307
0
            snmp_log(LOG_ERR, "could not get iterator for certs\n");
308
0
            netsnmp_certs_shutdown();
309
0
            return;
310
0
        }
311
1
        cert = ITERATOR_FIRST(itr);
312
1
        for( ; cert; cert = ITERATOR_NEXT(itr)) {
313
0
            netsnmp_cert_load_x509(cert);
314
0
        }
315
1
        ITERATOR_RELEASE(itr);
316
1
        DEBUGMSGT(("cert:dump",
317
1
                   "-------------------- Certificates -----------------\n"));
318
1
        netsnmp_cert_dump_all();
319
1
        DEBUGMSGT(("cert:dump",
320
1
                   "------------------------ End ----------------------\n"));
321
1
    }
322
2
}
323
324
/* #####################################################################
325
 *
326
 * cert container functions
327
 */
328
329
static netsnmp_container *
330
_get_cert_container(const char *use)
331
2.80k
{
332
2.80k
    netsnmp_container *c;
333
334
2.80k
    int rc;
335
336
2.80k
    c = netsnmp_container_find("certs:binary_array");
337
2.80k
    if (NULL == c) {
338
0
        snmp_log(LOG_ERR, "could not create container for %s\n", use);
339
0
        return NULL;
340
0
    }
341
2.80k
    c->container_name = strdup(use);
342
2.80k
    c->free_item = _cert_free;
343
2.80k
    c->compare = _cert_compare;
344
345
2.80k
    CONTAINER_SET_OPTIONS(c, CONTAINER_KEY_ALLOW_DUPLICATES, rc);
346
347
2.80k
    return c;
348
2.80k
}
349
350
static void
351
_setup_containers(void)
352
2.80k
{
353
2.80k
    netsnmp_container *additional_keys;
354
355
2.80k
    int rc;
356
357
2.80k
    _certs = _get_cert_container("netsnmp certificates");
358
2.80k
    if (NULL == _certs)
359
0
        return;
360
361
    /** additional keys: common name */
362
2.80k
    additional_keys = netsnmp_container_find("certs_cn:binary_array");
363
2.80k
    if (NULL == additional_keys) {
364
0
        snmp_log(LOG_ERR, "could not create CN container for certificates\n");
365
0
        netsnmp_certs_shutdown();
366
0
        return;
367
0
    }
368
2.80k
    additional_keys->container_name = strdup("certs_cn");
369
2.80k
    additional_keys->free_item = NULL;
370
2.80k
    additional_keys->compare = _cert_cn_compare;
371
2.80k
    CONTAINER_SET_OPTIONS(additional_keys, CONTAINER_KEY_ALLOW_DUPLICATES, rc);
372
2.80k
    netsnmp_container_add_index(_certs, additional_keys);
373
374
    /** additional keys: subject name */
375
2.80k
    additional_keys = netsnmp_container_find("certs_sn:binary_array");
376
2.80k
    if (NULL == additional_keys) {
377
0
        snmp_log(LOG_ERR, "could not create SN container for certificates\n");
378
0
        netsnmp_certs_shutdown();
379
0
        return;
380
0
    }
381
2.80k
    additional_keys->container_name = strdup("certs_sn");
382
2.80k
    additional_keys->free_item = NULL;
383
2.80k
    additional_keys->compare = _cert_sn_compare;
384
2.80k
    additional_keys->ncompare = _cert_sn_ncompare;
385
2.80k
    CONTAINER_SET_OPTIONS(additional_keys, CONTAINER_KEY_ALLOW_DUPLICATES, rc);
386
2.80k
    netsnmp_container_add_index(_certs, additional_keys);
387
388
    /** additional keys: file name */
389
2.80k
    additional_keys = netsnmp_container_find("certs_fn:binary_array");
390
2.80k
    if (NULL == additional_keys) {
391
0
        snmp_log(LOG_ERR, "could not create FN container for certificates\n");
392
0
        netsnmp_certs_shutdown();
393
0
        return;
394
0
    }
395
2.80k
    additional_keys->container_name = strdup("certs_fn");
396
2.80k
    additional_keys->free_item = NULL;
397
2.80k
    additional_keys->compare = _cert_fn_compare;
398
2.80k
    additional_keys->ncompare = _cert_fn_ncompare;
399
2.80k
    CONTAINER_SET_OPTIONS(additional_keys, CONTAINER_KEY_ALLOW_DUPLICATES, rc);
400
2.80k
    netsnmp_container_add_index(_certs, additional_keys);
401
402
2.80k
    _keys = netsnmp_container_find("cert_keys:binary_array");
403
2.80k
    if (NULL == _keys) {
404
0
        snmp_log(LOG_ERR, "could not create container for certificate keys\n");
405
0
        netsnmp_certs_shutdown();
406
0
        return;
407
0
    }
408
2.80k
    _keys->container_name = strdup("netsnmp certificate keys");
409
2.80k
    _keys->free_item = _key_free;
410
2.80k
    _keys->compare = _cert_fn_compare;
411
412
2.80k
    _setup_trusted_certs();
413
2.80k
}
414
415
netsnmp_container *
416
netsnmp_cert_map_container(void)
417
5.59k
{
418
5.59k
    return _maps;
419
5.59k
}
420
421
static netsnmp_cert *
422
_new_cert(const char *dirname, const char *filename, int certType, int offset,
423
          int allowed_uses, int hashType, const char *fingerprint,
424
          const char *common_name,  const char *subject)
425
0
{
426
0
    netsnmp_cert    *cert;
427
428
0
    if ((NULL == dirname) || (NULL == filename)) {
429
0
        snmp_log(LOG_ERR, "bad parameters to _new_cert\n");
430
0
        return NULL;
431
0
    }
432
433
0
    cert = SNMP_MALLOC_TYPEDEF(netsnmp_cert);
434
0
    if (NULL == cert) {
435
0
        snmp_log(LOG_ERR,"could not allocate memory for certificate at %s/%s\n",
436
0
                 dirname, filename);
437
0
        return NULL;
438
0
    }
439
440
0
    DEBUGMSGT(("9:cert:struct:new","new cert 0x%p for %s\n", cert, filename));
441
442
0
    cert->info.dir = strdup(dirname);
443
0
    cert->info.filename = strdup(filename);
444
    /* only the first certificate is allowed to be a remote peer */
445
0
    cert->info.allowed_uses = allowed_uses;
446
0
    cert->info.type = certType;
447
0
    cert->offset = offset;
448
0
    if (fingerprint) {
449
0
        cert->hash_type = hashType;
450
0
        cert->fingerprint = strdup(fingerprint);
451
0
    }
452
0
    if (common_name)
453
0
        cert->common_name = strdup(common_name);
454
0
    if (subject)
455
0
        cert->subject = strdup(subject);
456
457
0
    return cert;
458
0
}
459
460
static netsnmp_key *
461
_new_key(const char *dirname, const char *filename)
462
0
{
463
0
    netsnmp_key    *key;
464
0
    struct stat     fstat;
465
0
    char            fn[SNMP_MAXPATH];
466
467
0
    if ((NULL == dirname) || (NULL == filename)) {
468
0
        snmp_log(LOG_ERR, "bad parameters to _new_key\n");
469
0
        return NULL;
470
0
    }
471
472
    /** check file permissions */
473
0
    snprintf(fn, sizeof(fn), "%s/%s", dirname, filename);
474
0
    if (stat(fn, &fstat) != 0) {
475
0
        snmp_log(LOG_ERR, "could  not stat %s\n", fn);
476
0
        return NULL;
477
0
    }
478
479
0
#if !defined(_MSC_VER) && !defined(__MINGW32__)
480
0
    if ((fstat.st_mode & S_IROTH) || (fstat.st_mode & S_IWOTH)) {
481
0
        snmp_log(LOG_ERR,
482
0
                 "refusing to read world readable or writable key %s\n", fn);
483
0
        return NULL;
484
0
    }
485
0
#endif
486
487
0
    key = SNMP_MALLOC_TYPEDEF(netsnmp_key);
488
0
    if (NULL == key) {
489
0
        snmp_log(LOG_ERR, "could not allocate memory for key at %s/%s\n",
490
0
                 dirname, filename);
491
0
        return NULL;
492
0
    }
493
494
0
    DEBUGMSGT(("cert:key:struct:new","new key %p for %s\n", key, filename));
495
496
0
    key->info.type = NS_CERT_TYPE_KEY;
497
0
    key->info.dir = strdup(dirname);
498
0
    key->info.filename = strdup(filename);
499
0
    key->info.allowed_uses = NS_CERT_IDENTITY;
500
501
0
    return key;
502
0
}
503
504
void
505
netsnmp_cert_free(netsnmp_cert *cert)
506
0
{
507
0
    if (NULL == cert)
508
0
        return;
509
510
0
    DEBUGMSGT(("9:cert:struct:free","freeing cert %p, %s (fp %s; CN %s)\n",
511
0
               cert, cert->info.filename ? cert->info.filename : "UNK",
512
0
               cert->fingerprint ? cert->fingerprint : "UNK",
513
0
               cert->common_name ? cert->common_name : "UNK"));
514
515
0
    SNMP_FREE(cert->info.dir);
516
0
    SNMP_FREE(cert->info.filename);
517
0
    SNMP_FREE(cert->subject);
518
0
    SNMP_FREE(cert->issuer);
519
0
    SNMP_FREE(cert->fingerprint);
520
0
    SNMP_FREE(cert->common_name);
521
0
    if (cert->ocert)
522
0
        X509_free(cert->ocert);
523
0
    if (cert->key && cert->key->cert == cert)
524
0
        cert->key->cert = NULL;
525
526
0
    free(cert); /* SNMP_FREE not needed on parameters */
527
0
}
528
529
void
530
netsnmp_key_free(netsnmp_key *key)
531
0
{
532
0
    if (NULL == key)
533
0
        return;
534
535
0
    DEBUGMSGT(("cert:key:struct:free","freeing key %p, %s\n",
536
0
               key, key->info.filename ? key->info.filename : "UNK"));
537
538
0
    SNMP_FREE(key->info.dir);
539
0
    SNMP_FREE(key->info.filename);
540
0
    EVP_PKEY_free(key->okey);
541
0
    if (key->cert && key->cert->key == key)
542
0
        key->cert->key = NULL;
543
544
0
    free(key); /* SNMP_FREE not needed on parameters */
545
0
}
546
547
static void
548
_cert_free(void *cert, void *context)
549
0
{
550
0
    netsnmp_cert_free(cert);
551
0
}
552
553
static void
554
_key_free(void *key, void *context)
555
0
{
556
0
    netsnmp_key_free(key);
557
0
}
558
559
static int
560
_cert_compare(const void *p, const void *q)
561
0
{
562
0
    const netsnmp_cert *lhs = p, *rhs = q;
563
564
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
565
0
    netsnmp_assert((lhs->fingerprint != NULL) &&
566
0
                   (rhs->fingerprint != NULL));
567
568
    /** ignore hash type? */
569
0
    return strcmp(lhs->fingerprint, rhs->fingerprint);
570
0
}
571
572
static int
573
_cert_path_compare(const netsnmp_cert_common *lhs,
574
                   const netsnmp_cert_common *rhs)
575
0
{
576
0
    int rc;
577
578
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
579
    
580
    /** dir name first */
581
0
    rc = strcmp(lhs->dir, rhs->dir);
582
0
    if (rc)
583
0
        return rc;
584
585
    /** filename */
586
0
    return strcmp(lhs->filename, rhs->filename);
587
0
}
588
589
static int
590
_cert_cn_compare(const void *p, const void *q)
591
0
{
592
0
    const netsnmp_cert *lhs = p, *rhs = q;
593
0
    int rc;
594
0
    const char *lhcn, *rhcn;
595
596
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
597
598
0
    if (NULL == lhs->common_name)
599
0
        lhcn = "";
600
0
    else
601
0
        lhcn = lhs->common_name;
602
0
    if (NULL == rhs->common_name)
603
0
        rhcn = "";
604
0
    else
605
0
        rhcn = rhs->common_name;
606
607
0
    rc = strcmp(lhcn, rhcn);
608
0
    if (rc)
609
0
        return rc;
610
611
    /** in case of equal common names, sub-sort by path */
612
0
    return _cert_path_compare(&lhs->info, &rhs->info);
613
0
}
614
615
static int
616
_cert_sn_compare(const void *p, const void *q)
617
0
{
618
0
    const netsnmp_cert *lhs = p, *rhs = q;
619
0
    int rc;
620
0
    const char *lhsn, *rhsn;
621
622
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
623
624
0
    if (NULL == lhs->subject)
625
0
        lhsn = "";
626
0
    else
627
0
        lhsn = lhs->subject;
628
0
    if (NULL == rhs->subject)
629
0
        rhsn = "";
630
0
    else
631
0
        rhsn = rhs->subject;
632
633
0
    rc = strcmp(lhsn, rhsn);
634
0
    if (rc)
635
0
        return rc;
636
637
    /** in case of equal common names, sub-sort by path */
638
0
    return _cert_path_compare(&lhs->info, &rhs->info);
639
0
}
640
641
static int
642
_cert_fn_compare(const void *p, const void *q)
643
0
{
644
0
    const netsnmp_cert_common *lhs = p, *rhs = q;
645
0
    int rc;
646
647
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
648
649
0
    rc = strcmp(lhs->filename, rhs->filename);
650
0
    if (rc)
651
0
        return rc;
652
653
    /** in case of equal common names, sub-sort by dir */
654
0
    return strcmp(lhs->dir, rhs->dir);
655
0
}
656
657
static int
658
_cert_fn_ncompare(const void *p, const void *q)
659
0
{
660
0
    const netsnmp_cert_common *lhs = p, *rhs = q;
661
662
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
663
0
    netsnmp_assert((lhs->filename != NULL) && (rhs->filename != NULL));
664
665
0
    return strncmp(lhs->filename, rhs->filename, strlen(rhs->filename));
666
0
}
667
668
static int
669
_cert_sn_ncompare(const void *p, const void *q)
670
0
{
671
0
    const netsnmp_cert *lhs = p, *rhs = q;
672
673
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
674
0
    netsnmp_assert((lhs->subject != NULL) && (rhs->subject != NULL));
675
676
0
    return strncmp(lhs->subject, rhs->subject, strlen(rhs->subject));
677
0
}
678
679
static int
680
_cert_ext_type(const char *ext)
681
0
{
682
0
    int rc = se_find_value_in_slist("cert_types", ext);
683
0
    if (SE_DNE == rc)
684
0
        return NS_CERT_TYPE_UNKNOWN;
685
0
    return rc;
686
0
}
687
688
static int
689
_type_from_filename(const char *filename)
690
0
{
691
0
    char     *pos;
692
0
    int       type;
693
694
0
    if (NULL == filename)
695
0
        return NS_CERT_TYPE_UNKNOWN;
696
697
0
    pos = strrchr(filename, '.');
698
0
    if (NULL == pos)
699
0
        return NS_CERT_TYPE_UNKNOWN;
700
701
0
    type = _cert_ext_type(++pos);
702
0
    return type;
703
0
}
704
705
/*
706
 * filter functions; return 1 to include file, 0 to exclude
707
 */
708
static int _cert_cert_filter(const void *text, void *ctx)
709
0
{
710
0
    const char *filename = text;
711
0
    int  len = strlen(filename);
712
0
    const char *pos;
713
714
0
    if (len < 5) /* shortest name: x.YYY */
715
0
        return 0;
716
717
0
    pos = strrchr(filename, '.');
718
0
    if (NULL == pos)
719
0
        return 0;
720
721
0
    if (_cert_ext_type(++pos) != NS_CERT_TYPE_UNKNOWN)
722
0
        return 1;
723
724
0
    return 0;
725
0
}
726
727
/* #####################################################################
728
 *
729
 * cert index functions
730
 *
731
 * This code mimics what the mib index code does. The persistent
732
 * directory will have a subdirectory named 'cert_indexes'. Inside
733
 * this directory will be some number of files with ascii numeric
734
 * names (0, 1, 2, etc). Each of these files will start with a line
735
 * with the text "DIR ", followed by a directory name. The rest of the
736
 * file will be certificate fields and the certificate file name, one
737
 * certificate per line. The numeric file name is the integer 'directory
738
 * index'.
739
 */
740
741
/**
742
 * _certindex_add
743
 *
744
 * add a directory name to the indexes
745
 */
746
static int
747
_certindex_add( const char *dirname, int i )
748
0
{
749
0
    int rc;
750
0
    char *dirname_copy = strdup(dirname);
751
752
0
    if ( i == -1 ) {
753
0
        int max = se_find_free_value_in_list(_certindexes);
754
0
        if (SE_DNE == max)
755
0
            i = 0;
756
0
        else
757
0
            i = max;
758
0
    }
759
760
0
    DEBUGMSGT(("cert:index:add","dir %s at index %d\n", dirname, i ));
761
0
    rc = se_add_pair_to_list(&_certindexes, dirname_copy, i);
762
0
    if (SE_OK != rc) {
763
0
        snmp_log(LOG_ERR, "adding certindex dirname failed; "
764
0
                 "%d (%s) not added\n", i, dirname);
765
0
        return -1;
766
0
    }
767
768
0
    return i;
769
0
}
770
771
/**
772
 * _certindex_load
773
 *
774
 * read in the existing indexes
775
 */
776
static void
777
_certindexes_load( void )
778
2
{
779
2
    DIR *dir;
780
2
    struct dirent *file;
781
2
    FILE *fp;
782
2
    char filename[SNMP_MAXPATH], line[300];
783
2
    int  i;
784
2
    char *cp, *pos;
785
786
    /*
787
     * Open the CERT index directory, or create it (empty)
788
     */
789
2
    snprintf( filename, sizeof(filename), "%s/cert_indexes",
790
2
              get_persistent_directory());
791
2
    filename[sizeof(filename)-1] = 0;
792
2
    dir = opendir( filename );
793
2
    if ( dir == NULL ) {
794
1
        DEBUGMSGT(("cert:index:load",
795
1
                   "creating new cert_indexes directory\n"));
796
1
        mkdirhier( filename, NETSNMP_AGENT_DIRECTORY_MODE, 0);
797
1
        return;
798
1
    }
799
800
    /*
801
     * Create a list of which directory each file refers to
802
     */
803
3
    while ((file = readdir( dir ))) {
804
2
        if ( !isdigit(0xFF & file->d_name[0]))
805
2
            continue;
806
0
        i = atoi( file->d_name );
807
808
0
        snprintf( filename, sizeof(filename), "%s/cert_indexes/%d",
809
0
              get_persistent_directory(), i );
810
0
        filename[sizeof(filename)-1] = 0;
811
0
        fp = fopen( filename, "r" );
812
0
        if ( !fp ) {
813
0
            DEBUGMSGT(("cert:index:load", "error opening index (%d)\n", i));
814
0
            continue;
815
0
        }
816
0
        cp = fgets( line, sizeof(line), fp );
817
0
        if ( cp ) {
818
0
            line[strlen(line)-1] = 0;
819
0
            pos = strrchr(line, ' ');
820
0
            if (pos)
821
0
                *pos = '\0';
822
0
            DEBUGMSGT(("9:cert:index:load","adding (%d) %s\n", i, line));
823
0
            (void)_certindex_add( line+4, i );  /* Skip 'DIR ' */
824
0
        } else {
825
0
            DEBUGMSGT(("cert:index:load", "Empty index (%d)\n", i));
826
0
        }
827
0
        fclose( fp );
828
0
    }
829
1
    closedir( dir );
830
1
}
831
832
/**
833
 * _certindex_lookup
834
 *
835
 * find index for a directory
836
 */
837
static char *
838
_certindex_lookup( const char *dirname )
839
0
{
840
0
    int i;
841
0
    char filename[SNMP_MAXPATH];
842
843
844
0
    i = se_find_value_in_list(_certindexes, dirname);
845
0
    if (SE_DNE == i) {
846
0
        DEBUGMSGT(("9:cert:index:lookup","%s : (none)\n", dirname));
847
0
        return NULL;
848
0
    }
849
850
0
    snprintf(filename, sizeof(filename), "%s/cert_indexes/%d",
851
0
             get_persistent_directory(), i);
852
0
    filename[sizeof(filename)-1] = 0;
853
0
    DEBUGMSGT(("cert:index:lookup", "%s (%d) %s\n", dirname, i, filename ));
854
0
    return strdup(filename);
855
0
}
856
857
static FILE *
858
_certindex_new( const char *dirname )
859
0
{
860
0
    FILE *fp;
861
0
    char  filename[SNMP_MAXPATH], *cp;
862
0
    int   i;
863
864
0
    cp = _certindex_lookup( dirname );
865
0
    if (!cp) {
866
0
        i  = _certindex_add( dirname, -1 );
867
0
        if (-1 == i)
868
0
            return NULL; /* msg already logged */
869
0
        snprintf( filename, sizeof(filename), "%s/cert_indexes/%d",
870
0
                  get_persistent_directory(), i );
871
0
        filename[sizeof(filename)-1] = 0;
872
0
        cp = filename;
873
0
    }
874
0
    DEBUGMSGT(("9:cert:index:new", "%s (%s)\n", dirname, cp ));
875
0
    fp = fopen( cp, "w" );
876
0
    if (fp)
877
0
        fprintf( fp, "DIR %s %d\n", dirname, CERT_INDEX_FORMAT );
878
0
    else
879
0
        DEBUGMSGTL(("cert:index", "error opening new index file %s\n", dirname));
880
881
0
    if (cp != filename)
882
0
        free(cp);
883
884
0
    return fp;
885
0
}
886
887
/* #####################################################################
888
 *
889
 * certificate utility functions
890
 *
891
 */
892
static BIO *
893
netsnmp_open_bio(const char *dir, const char *filename)
894
0
{
895
0
    BIO            *certbio;
896
0
    char            file[SNMP_MAXPATH];
897
898
0
    DEBUGMSGT(("9:cert:read", "Checking file %s\n", filename));
899
900
0
    certbio = BIO_new(BIO_s_file());
901
0
    if (NULL == certbio) {
902
0
        snmp_log(LOG_ERR, "error creating BIO\n");
903
0
        return NULL;
904
0
    }
905
906
0
    snprintf(file, sizeof(file),"%s/%s", dir, filename);
907
0
    if (BIO_read_filename(certbio, file) <=0) {
908
0
        snmp_log(LOG_ERR, "error reading certificate/key %s into BIO\n", file);
909
0
        BIO_vfree(certbio);
910
0
        return NULL;
911
0
    }
912
913
0
    return certbio;
914
0
}
915
916
static void
917
netsnmp_ocert_parse(netsnmp_cert *cert, X509 *ocert)
918
0
{
919
0
    int             is_ca;
920
921
0
    cert->ocert = ocert;
922
923
    /*
924
     * X509_check_ca return codes:
925
     * 0 not a CA
926
     * 1 is a CA
927
     * 2 basicConstraints absent so "maybe" a CA
928
     * 3 basicConstraints absent but self signed V1.
929
     * 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
930
     * 5 outdated Netscape Certificate Type CA extension.
931
     */
932
0
    is_ca = X509_check_ca(ocert);
933
0
    if (1 == is_ca)
934
0
        cert->info.allowed_uses |= NS_CERT_CA;
935
936
0
    if (NULL == cert->subject) {
937
0
        cert->subject = X509_NAME_oneline(X509_get_subject_name(ocert), NULL,
938
0
                                          0);
939
0
        DEBUGMSGT(("9:cert:add:subject", "subject name: %s\n", cert->subject));
940
0
    }
941
942
0
    if (NULL == cert->issuer) {
943
0
        cert->issuer = X509_NAME_oneline(X509_get_issuer_name(ocert), NULL, 0);
944
0
        if (strcmp(cert->subject, cert->issuer) == 0) {
945
0
            free(cert->issuer);
946
0
            cert->issuer = strdup("self-signed");
947
0
        }
948
0
        DEBUGMSGT(("9:cert:add:issuer", "CA issuer: %s\n", cert->issuer));
949
0
    }
950
951
0
    if (NULL == cert->fingerprint) {
952
0
        cert->hash_type = NS_HASH_SHA1;
953
0
        cert->fingerprint =
954
0
            netsnmp_openssl_cert_get_fingerprint(ocert, cert->hash_type);
955
0
    }
956
957
0
    if (NULL == cert->common_name) {
958
0
        cert->common_name =netsnmp_openssl_cert_get_commonName(ocert, NULL,
959
0
                                                               NULL);
960
0
        DEBUGMSGT(("9:cert:add:name","%s\n", cert->common_name));
961
0
    }
962
963
0
}
964
965
static X509 *
966
netsnmp_ocert_get(netsnmp_cert *cert)
967
0
{
968
0
    BIO            *certbio;
969
0
    X509           *ocert = NULL;
970
0
    X509           *ncert = NULL;
971
0
    EVP_PKEY       *okey = NULL;
972
973
0
    if (NULL == cert)
974
0
        return NULL;
975
976
0
    if (cert->ocert)
977
0
        return cert->ocert;
978
979
0
    if (NS_CERT_TYPE_UNKNOWN == cert->info.type) {
980
0
        cert->info.type = _type_from_filename(cert->info.filename);
981
0
        if (NS_CERT_TYPE_UNKNOWN == cert->info.type) {
982
0
            snmp_log(LOG_ERR, "unknown certificate type %d for %s\n",
983
0
                     cert->info.type, cert->info.filename);
984
0
            return NULL;
985
0
        }
986
0
    }
987
988
0
    certbio = netsnmp_open_bio(cert->info.dir, cert->info.filename);
989
0
    if (!certbio) {
990
0
        return NULL;
991
0
    }
992
993
0
    switch (cert->info.type) {
994
995
0
        case NS_CERT_TYPE_DER:
996
0
            (void)BIO_seek(certbio, cert->offset);
997
0
            ocert = d2i_X509_bio(certbio,NULL); /* DER/ASN1 */
998
0
            if (NULL != ocert)
999
0
                break;
1000
            /* Check for PEM if DER didn't work */
1001
0
            NETSNMP_FALLTHROUGH;
1002
1003
0
        case NS_CERT_TYPE_PEM:
1004
0
            (void)BIO_seek(certbio, cert->offset);
1005
0
            ocert = ncert = PEM_read_bio_X509_AUX(certbio, NULL, NULL, NULL);
1006
0
            if (NULL == ocert)
1007
0
                break;
1008
0
            if (NS_CERT_TYPE_DER == cert->info.type) {
1009
0
                DEBUGMSGT(("9:cert:read", "Changing type from DER to PEM\n"));
1010
0
                cert->info.type = NS_CERT_TYPE_PEM;
1011
0
            }
1012
            /** check for private key too, but only if we're the first certificate */
1013
0
            if (0 == cert->offset && NULL == cert->key) {
1014
0
                okey = PEM_read_bio_PrivateKey(certbio, NULL, NULL, NULL);
1015
0
                if (NULL != okey) {
1016
0
                    netsnmp_key  *key;
1017
0
                    DEBUGMSGT(("cert:read:key", "found key with cert in %s\n",
1018
0
                               cert->info.filename));
1019
0
                    key = _new_key(cert->info.dir, cert->info.filename);
1020
0
                    if (NULL != key) {
1021
0
                        key->okey = okey;
1022
0
                        if (-1 == CONTAINER_INSERT(_keys, key)) {
1023
0
                            DEBUGMSGT(("cert:read:key:add",
1024
0
                                       "error inserting key into container\n"));
1025
0
                            netsnmp_key_free(key);
1026
0
                            key = NULL;
1027
0
                        }
1028
0
                        else {
1029
0
                            DEBUGMSGT(("cert:read:partner", "%s match found!\n",
1030
0
                                       cert->info.filename));
1031
0
                            key->cert = cert;
1032
0
                            cert->key = key;
1033
0
                            cert->info.allowed_uses |= NS_CERT_IDENTITY;
1034
0
                        }
1035
0
                    }
1036
0
                } /* null return from read */
1037
0
            } /* null key */
1038
0
            break;
1039
#ifdef CERT_PKCS12_SUPPORT_MAYBE_LATER
1040
        case NS_CERT_TYPE_PKCS12:
1041
            (void)BIO_seek(certbio, cert->offset);
1042
            PKCS12 *p12 = d2i_PKCS12_bio(certbio, NULL);
1043
            if ( (NULL != p12) && (PKCS12_verify_mac(p12, "", 0) ||
1044
                                   PKCS12_verify_mac(p12, NULL, 0)))
1045
                PKCS12_parse(p12, "", NULL, &cert, NULL);
1046
            break;
1047
#endif
1048
0
        default:
1049
0
            snmp_log(LOG_ERR, "unknown certificate type %d for %s\n",
1050
0
                     cert->info.type, cert->info.filename);
1051
0
    }
1052
1053
0
    BIO_vfree(certbio);
1054
1055
0
    if (NULL == ocert) {
1056
0
        snmp_log(LOG_ERR, "error parsing certificate file %s\n",
1057
0
                 cert->info.filename);
1058
0
        return NULL;
1059
0
    }
1060
1061
0
    netsnmp_ocert_parse(cert, ocert);
1062
1063
0
    return ocert;
1064
0
}
1065
1066
EVP_PKEY *
1067
netsnmp_okey_get(netsnmp_key  *key)
1068
0
{
1069
0
    BIO            *keybio;
1070
0
    EVP_PKEY       *okey;
1071
1072
0
    if (NULL == key)
1073
0
        return NULL;
1074
1075
0
    if (key->okey)
1076
0
        return key->okey;
1077
1078
0
    keybio = netsnmp_open_bio(key->info.dir, key->info.filename);
1079
0
    if (!keybio) {
1080
0
        return NULL;
1081
0
    }
1082
1083
0
    okey = PEM_read_bio_PrivateKey(keybio, NULL, NULL, NULL);
1084
0
    if (NULL == okey)
1085
0
        snmp_log(LOG_ERR, "error parsing certificate file %s\n",
1086
0
                 key->info.filename);
1087
0
    else
1088
0
        key->okey = okey;
1089
1090
0
    BIO_vfree(keybio);
1091
1092
0
    return okey;
1093
0
}
1094
1095
static netsnmp_cert *
1096
_find_issuer(netsnmp_cert *cert)
1097
0
{
1098
0
    netsnmp_void_array *matching;
1099
0
    netsnmp_cert       *candidate, *issuer = NULL;
1100
0
    int                 i;
1101
1102
0
    if ((NULL == cert) || (NULL == cert->issuer))
1103
0
        return NULL;
1104
1105
    /** find matching subject names */
1106
1107
0
    matching = _cert_find_subset_sn(cert->issuer);
1108
0
    if (NULL == matching)
1109
0
        return NULL;
1110
1111
    /** check each to see if it's the issuer */
1112
0
    for ( i=0; (NULL == issuer) && (i < matching->size); ++i) {
1113
        /** make sure we have ocert */
1114
0
        candidate = (netsnmp_cert*)matching->array[i];
1115
0
        if ((NULL == candidate->ocert) &&
1116
0
            (netsnmp_ocert_get(candidate) == NULL))
1117
0
            continue;
1118
1119
        /** compare **/
1120
0
        if (netsnmp_openssl_cert_issued_by(candidate->ocert, cert->ocert))
1121
0
            issuer = candidate;
1122
0
    } /** candidate loop */
1123
1124
0
    free(matching->array);
1125
0
    free(matching);
1126
1127
0
    return issuer;
1128
0
}
1129
1130
0
#define CERT_LOAD_OK       0
1131
0
#define CERT_LOAD_ERR     -1
1132
0
#define CERT_LOAD_PARTIAL -2
1133
int
1134
netsnmp_cert_load_x509(netsnmp_cert *cert)
1135
0
{
1136
0
    int rc = CERT_LOAD_OK;
1137
1138
    /** load ocert */
1139
0
    if ((NULL == cert->ocert) && (netsnmp_ocert_get(cert) == NULL)) {
1140
0
        DEBUGMSGT(("cert:load:err", "couldn't load cert for %s\n",
1141
0
                   cert->info.filename));
1142
0
        rc = CERT_LOAD_ERR;
1143
0
    }
1144
1145
    /** load key */
1146
0
    if ((NULL != cert->key) && (NULL == cert->key->okey) &&
1147
0
        (netsnmp_okey_get(cert->key) == NULL)) {
1148
0
        DEBUGMSGT(("cert:load:err", "couldn't load key for cert %s\n",
1149
0
                   cert->info.filename));
1150
0
        rc = CERT_LOAD_ERR;
1151
0
    }
1152
1153
    /** make sure we have cert chain */
1154
0
    for (; cert && cert->issuer; cert = cert->issuer_cert) {
1155
        /** skip self signed */
1156
0
        if (strcmp(cert->issuer, "self-signed") == 0) {
1157
0
            netsnmp_assert(cert->issuer_cert == NULL);
1158
0
            break;
1159
0
        }
1160
        /** get issuer cert */
1161
0
        if (NULL == cert->issuer_cert) {
1162
0
            cert->issuer_cert =  _find_issuer(cert);
1163
0
            if (NULL == cert->issuer_cert) {
1164
0
                DEBUGMSGT(("cert:load:warn",
1165
0
                           "couldn't load full CA chain for cert %s\n",
1166
0
                           cert->info.filename));
1167
0
                rc = CERT_LOAD_PARTIAL;
1168
0
                break;
1169
0
            }
1170
0
        }
1171
        /** get issuer ocert */
1172
0
        if ((NULL == cert->issuer_cert->ocert) &&
1173
0
            (netsnmp_ocert_get(cert->issuer_cert) == NULL)) {
1174
0
            DEBUGMSGT(("cert:load:warn", "couldn't load full cert chain for %s\n",
1175
0
                       cert->info.filename));
1176
0
            rc = CERT_LOAD_PARTIAL;
1177
0
            break;
1178
0
        }
1179
0
    } /* cert CA for loop */
1180
1181
0
    return rc;
1182
0
}
1183
1184
static void
1185
_find_partner(netsnmp_cert *cert, netsnmp_key *key)
1186
0
{
1187
0
    netsnmp_void_array *matching = NULL;
1188
0
    char                filename[NAME_MAX], *pos;
1189
1190
0
    if ((cert && key) || (!cert && ! key)) {
1191
0
        DEBUGMSGT(("cert:partner", "bad parameters searching for partner\n"));
1192
0
        return;
1193
0
    }
1194
1195
0
    if (key) {
1196
0
        if (key->cert) {
1197
0
            DEBUGMSGT(("cert:partner", "key already has partner\n"));
1198
0
            return;
1199
0
        }
1200
0
        DEBUGMSGT(("9:cert:partner", "%s looking for partner near %s\n",
1201
0
                   key->info.filename, key->info.dir));
1202
0
        snprintf(filename, sizeof(filename), "%s", key->info.filename);
1203
0
        pos = strrchr(filename, '.');
1204
0
        if (NULL == pos)
1205
0
            return;
1206
0
        *pos = 0;
1207
1208
0
        matching = _cert_reduce_subset_first(_cert_find_subset_fn( filename,
1209
0
                                             key->info.dir ));
1210
0
        if (!matching)
1211
0
            return;
1212
0
        if (1 == matching->size) {
1213
0
            cert = (netsnmp_cert*)matching->array[0];
1214
0
            if (NULL == cert->key) {
1215
0
                DEBUGMSGT(("cert:partner", "%s match found!\n",
1216
0
                           cert->info.filename));
1217
0
                key->cert = cert;
1218
0
                cert->key = key;
1219
0
                cert->info.allowed_uses |= NS_CERT_IDENTITY;
1220
0
            }
1221
0
            else if (cert->key != key)
1222
0
                snmp_log(LOG_ERR, "%s matching cert already has partner\n",
1223
0
                         cert->info.filename);
1224
0
        }
1225
0
        else
1226
0
            DEBUGMSGT(("cert:partner", "%s matches multiple certs\n",
1227
0
                          key->info.filename));
1228
0
    }
1229
0
    else if (cert) {
1230
0
        if (cert->key) {
1231
0
            DEBUGMSGT(("cert:partner", "cert already has partner\n"));
1232
0
            return;
1233
0
        }
1234
0
        DEBUGMSGT(("9:cert:partner", "%s looking for partner\n",
1235
0
                   cert->info.filename));
1236
0
        snprintf(filename, sizeof(filename), "%s", cert->info.filename);
1237
0
        pos = strrchr(filename, '.');
1238
0
        if (NULL == pos)
1239
0
            return;
1240
0
        *pos = 0;
1241
1242
0
        matching = _key_find_subset(filename);
1243
0
        if (!matching)
1244
0
            return;
1245
0
        if (1 == matching->size) {
1246
0
            key = (netsnmp_key*)matching->array[0];
1247
0
            if (NULL == key->cert) {
1248
0
                DEBUGMSGT(("cert:partner", "%s found!\n", cert->info.filename));
1249
0
                key->cert = cert;
1250
0
                cert->key = key;
1251
0
            }
1252
0
            else if (key->cert != cert)
1253
0
                snmp_log(LOG_ERR, "%s matching key already has partner\n",
1254
0
                         cert->info.filename);
1255
0
        }
1256
0
        else
1257
0
            DEBUGMSGT(("cert:partner", "%s matches multiple keys\n",
1258
0
                       cert->info.filename));
1259
0
    }
1260
    
1261
0
    if (matching) {
1262
0
        free(matching->array);
1263
0
        free(matching);
1264
0
    }
1265
0
}
1266
1267
static netsnmp_key *
1268
_add_key(EVP_PKEY *okey, const char* dirname, const char* filename, FILE *index)
1269
0
{
1270
0
    netsnmp_key  *key;
1271
1272
0
    key = _new_key(dirname, filename);
1273
0
    if (NULL == key) {
1274
0
        return NULL;
1275
0
    }
1276
1277
0
    key->okey = okey;
1278
1279
0
    if (-1 == CONTAINER_INSERT(_keys, key)) {
1280
0
        DEBUGMSGT(("cert:key:file:add:err",
1281
0
                   "error inserting key into container\n"));
1282
0
        netsnmp_key_free(key);
1283
0
        key = NULL;
1284
0
    }
1285
0
    if (index) {
1286
0
        fprintf(index, "k:%s\n", filename);
1287
0
    }
1288
1289
0
    return key;
1290
0
}
1291
1292
static netsnmp_cert *
1293
_add_cert(X509 *ocert, const char* dirname, const char* filename, int type, int offset,
1294
          int allowed_uses, FILE *index)
1295
0
{
1296
0
    netsnmp_cert *cert;
1297
1298
0
    cert = _new_cert(dirname, filename, type, offset,
1299
0
                     allowed_uses, -1, NULL, NULL, NULL);
1300
0
    if (NULL == cert)
1301
0
        return NULL;
1302
1303
0
    netsnmp_ocert_parse(cert, ocert);
1304
1305
0
    if (-1 == CONTAINER_INSERT(_certs, cert)) {
1306
0
        DEBUGMSGT(("cert:file:add:err",
1307
0
                   "error inserting cert into container\n"));
1308
0
        netsnmp_cert_free(cert);
1309
0
        return NULL;
1310
0
    }
1311
1312
0
    if (index) {
1313
        /** filename = NAME_MAX = 255 */
1314
        /** fingerprint max = 64*3=192 for sha512 */
1315
        /** common name / CN  = 64 */
1316
0
        if (cert)
1317
0
            fprintf(index, "c:%s %d %d %d %d %s '%s' '%s'\n", filename,
1318
0
                    cert->info.type, cert->offset, cert->info.allowed_uses,
1319
0
                    cert->hash_type, cert->fingerprint,
1320
0
                    cert->common_name, cert->subject);
1321
0
    }
1322
1323
0
    return cert;
1324
0
}
1325
1326
static int
1327
_add_certfile(const char* dirname, const char* filename, FILE *index)
1328
0
{
1329
0
    BIO          *certbio;
1330
0
    X509         *ocert = NULL;
1331
0
    X509         *ncert;
1332
0
    EVP_PKEY     *okey = NULL;
1333
0
    netsnmp_cert *cert = NULL;
1334
0
    netsnmp_key  *key = NULL;
1335
0
    char          certfile[SNMP_MAXPATH];
1336
0
    int           type;
1337
0
    int           offset = 0;
1338
1339
0
    if (((const void*)NULL == dirname) || (NULL == filename))
1340
0
        return -1;
1341
1342
0
    type = _type_from_filename(filename);
1343
0
    if (type == NS_CERT_TYPE_UNKNOWN) {
1344
0
        snmp_log(LOG_ERR, "certificate file '%s' type not recognised, ignoring\n", filename);
1345
0
        return -1;
1346
0
    }
1347
1348
0
    certbio = netsnmp_open_bio(dirname, filename);
1349
0
    if (!certbio) {
1350
0
        return -1;
1351
0
    }
1352
1353
0
    switch (type) {
1354
1355
0
       case NS_CERT_TYPE_KEY: 
1356
1357
0
           okey = PEM_read_bio_PrivateKey(certbio, NULL, NULL, NULL);
1358
0
           if (NULL == okey)
1359
0
               snmp_log(LOG_ERR, "error parsing key file %s\n", filename);
1360
0
           else {
1361
0
               key = _add_key(okey, dirname, filename, index);
1362
0
               if (NULL == key) {
1363
0
                   EVP_PKEY_free(okey);
1364
0
                      okey = NULL;
1365
0
               }
1366
0
           }
1367
0
           break;
1368
1369
0
        case NS_CERT_TYPE_DER:
1370
1371
0
            ocert = d2i_X509_bio(certbio, NULL); /* DER/ASN1 */
1372
0
            if (NULL != ocert) {
1373
0
                if (!_add_cert(ocert, dirname, filename, type, 0,
1374
0
                               NS_CERT_REMOTE_PEER, index)) {
1375
0
                    X509_free(ocert);
1376
0
                    ocert = NULL;
1377
0
                }
1378
0
                break;
1379
0
            }
1380
0
            (void)BIO_reset(certbio);
1381
            /* Check for PEM if DER didn't work */
1382
0
            NETSNMP_FALLTHROUGH;
1383
1384
0
        case NS_CERT_TYPE_PEM:
1385
1386
0
            if (NS_CERT_TYPE_DER == type) {
1387
0
                DEBUGMSGT(("9:cert:read", "Changing type from DER to PEM\n"));
1388
0
                type = NS_CERT_TYPE_PEM;
1389
0
            }
1390
1391
            /* read the private key first so we can record this in the index */
1392
0
            okey = PEM_read_bio_PrivateKey(certbio, NULL, NULL, NULL);
1393
1394
0
            (void)BIO_reset(certbio);
1395
1396
            /* certs are read after the key */
1397
0
      ocert = ncert = PEM_read_bio_X509_AUX(certbio, NULL, NULL, NULL);
1398
0
            if (NULL != ocert) {
1399
0
                cert = _add_cert(ncert, dirname, filename, type, 0,
1400
0
                                 okey ? NS_CERT_IDENTITY | NS_CERT_REMOTE_PEER :
1401
0
                                 NS_CERT_REMOTE_PEER, index);
1402
0
                if (NULL == cert) {
1403
0
                    X509_free(ocert);
1404
0
                    ocert = ncert = NULL;
1405
0
                }
1406
0
            }
1407
0
            while (NULL != ncert) {
1408
0
                offset = BIO_tell(certbio);
1409
0
                ncert = PEM_read_bio_X509_AUX(certbio, NULL, NULL, NULL);
1410
0
                if (ncert) {
1411
0
                    if (NULL == _add_cert(ncert, dirname, filename, type, offset, 0, index)) {
1412
0
                        X509_free(ncert);
1413
0
                        ncert = NULL;
1414
0
                    }
1415
0
                }
1416
0
            }
1417
1418
0
            if (okey && cert) {
1419
0
                DEBUGMSGT(("cert:read:key", "found key with cert in %s\n",
1420
0
                           cert->info.filename));
1421
0
                key = _add_key(okey, dirname, filename, NULL);
1422
0
                if (NULL != key) {
1423
0
                    DEBUGMSGT(("cert:read:partner", "%s match found!\n",
1424
0
                               cert->info.filename));
1425
0
                    key->cert = cert;
1426
0
                    cert->key = key;
1427
0
                }
1428
0
                else {
1429
0
                    EVP_PKEY_free(okey);
1430
0
                    okey = NULL;
1431
0
                }
1432
0
            } else if (okey) {
1433
0
                EVP_PKEY_free(okey);
1434
0
                okey = NULL;
1435
0
            }
1436
1437
0
            break;
1438
1439
#ifdef CERT_PKCS12_SUPPORT_MAYBE_LATER
1440
        case NS_CERT_TYPE_PKCS12:
1441
#endif
1442
1443
0
        default:
1444
0
            break;
1445
0
    }
1446
1447
0
    BIO_vfree(certbio);
1448
1449
0
    if ((NULL == ocert) && (NULL == okey)) {
1450
0
        snmp_log(LOG_ERR, "certificate file '%s' contained neither certificate nor key, ignoring\n", certfile);
1451
0
        return -1;
1452
0
    }
1453
1454
0
    return 0;
1455
0
}
1456
1457
static int
1458
_cert_read_index(const char *dirname, struct stat *dirstat)
1459
0
{
1460
0
    FILE           *index;
1461
0
    char           *idxname, *pos;
1462
0
    struct stat     idx_stat;
1463
0
    char            tmpstr[SNMP_MAXPATH + 5], filename[NAME_MAX];
1464
0
    char            fingerprint[EVP_MAX_MD_SIZE*3], common_name[64+1], type_str[15];
1465
0
    char            subject[SNMP_MAXBUF_SMALL], hash_str[15], offset_str[15];
1466
0
    char            allowed_uses_str[15];
1467
0
    ssize_t         offset;
1468
0
    int             count = 0, type, allowed_uses, hash, version;
1469
0
    netsnmp_cert    *cert;
1470
0
    netsnmp_key     *key;
1471
0
    netsnmp_container *newer, *found;
1472
1473
0
    netsnmp_assert(NULL != dirname);
1474
1475
0
    idxname = _certindex_lookup( dirname );
1476
0
    if (NULL == idxname) {
1477
0
        DEBUGMSGT(("cert:index:parse", "no index for cert directory\n"));
1478
0
        return -1;
1479
0
    }
1480
1481
    /*
1482
     * see if directory has been modified more recently than the index
1483
     */
1484
0
    if (stat(idxname, &idx_stat) != 0) {
1485
0
        DEBUGMSGT(("cert:index:parse", "error getting index file stats\n"));
1486
0
        SNMP_FREE(idxname);
1487
0
        return -1;
1488
0
    }
1489
1490
#if (defined(WIN32) || defined(cygwin))
1491
    /* For Win32 platforms, the directory does not maintain a last modification
1492
     * date that we can compare with the modification date of the .index file.
1493
     */
1494
#else
1495
0
    if (dirstat->st_mtime >= idx_stat.st_mtime) {
1496
0
        DEBUGMSGT(("cert:index:parse", "Index outdated; dir modified\n"));
1497
0
        SNMP_FREE(idxname);
1498
0
        return -1;
1499
0
    }
1500
0
#endif
1501
1502
    /*
1503
     * dir mtime doesn't change when files are touched, so we need to check
1504
     * each file against the index in case a file has been modified.
1505
     */
1506
0
    newer =
1507
0
        netsnmp_directory_container_read_some(NULL, dirname,
1508
0
                                              _time_filter, &idx_stat,
1509
0
                                              NETSNMP_DIR_NSFILE |
1510
0
                                              NETSNMP_DIR_NSFILE_STATS |
1511
0
                                              NETSNMP_DIR_ALLOW_DUPLICATES);
1512
0
    if (newer) {
1513
0
        DEBUGMSGT(("cert:index:parse", "Index outdated; files modified\n"));
1514
0
        CONTAINER_FREE_ALL(newer, NULL);
1515
0
        CONTAINER_FREE(newer);
1516
0
        SNMP_FREE(idxname);
1517
0
        return -1;
1518
0
    }
1519
1520
0
    DEBUGMSGT(("cert:index:parse", "The index for %s looks good\n", dirname));
1521
1522
0
    index = fopen(idxname, "r");
1523
0
    if (NULL == index) {
1524
0
        snmp_log(LOG_ERR, "cert:index:parse can't open index for %s\n",
1525
0
            dirname);
1526
0
        SNMP_FREE(idxname);
1527
0
        return -1;
1528
0
    }
1529
1530
0
    found = _get_cert_container(idxname);
1531
1532
    /*
1533
     * check index format version
1534
     */
1535
0
    NETSNMP_IGNORE_RESULT(fgets(tmpstr, sizeof(tmpstr), index));
1536
0
    pos = strrchr(tmpstr, ' ');
1537
0
    if (pos) {
1538
0
        ++pos;
1539
0
        version = atoi(pos);
1540
0
    }
1541
0
    if ((NULL == pos) || (version != CERT_INDEX_FORMAT)) {
1542
0
        DEBUGMSGT(("cert:index:add", "missing or wrong index format!\n"));
1543
0
        fclose(index);
1544
0
        SNMP_FREE(idxname);
1545
0
        count = -1;
1546
0
        goto free_cert_container;
1547
0
    }
1548
0
    while (1) {
1549
0
        if (NULL == fgets(tmpstr, sizeof(tmpstr), index))
1550
0
            break;
1551
1552
0
        if ('c' == tmpstr[0]) {
1553
0
            pos = &tmpstr[2];
1554
0
            if ((NULL == (pos=copy_nword(pos, filename, sizeof(filename)))) ||
1555
0
                (NULL == (pos=copy_nword(pos, type_str, sizeof(type_str)))) ||
1556
0
                (NULL == (pos=copy_nword(pos, offset_str, sizeof(offset_str)))) ||
1557
0
                (NULL == (pos=copy_nword(pos, allowed_uses_str, sizeof(allowed_uses_str)))) ||
1558
0
                (NULL == (pos=copy_nword(pos, hash_str, sizeof(hash_str)))) ||
1559
0
                (NULL == (pos=copy_nword(pos, fingerprint,
1560
0
                                         sizeof(fingerprint)))) ||
1561
0
                (NULL == (pos=copy_nword(pos, common_name,
1562
0
                                           sizeof(common_name)))) ||
1563
0
                (NULL != copy_nword(pos, subject, sizeof(subject)))) {
1564
0
                snmp_log(LOG_ERR, "_cert_read_index: error parsing line: %s\n",
1565
0
                         tmpstr);
1566
0
                count = -1;
1567
0
                break;
1568
0
            }
1569
0
            type = atoi(type_str);
1570
0
            offset = atoi(offset_str);
1571
0
            allowed_uses = atoi(allowed_uses_str);
1572
0
            hash = atoi(hash_str);
1573
0
            cert = _new_cert(dirname, filename, type, offset, allowed_uses, hash,
1574
0
                             fingerprint, common_name, subject);
1575
0
            if (cert && 0 == CONTAINER_INSERT(found, cert))
1576
0
                ++count;
1577
0
            else {
1578
0
                DEBUGMSGT(("cert:index:add",
1579
0
                           "error inserting cert into container\n"));
1580
0
                netsnmp_cert_free(cert);
1581
0
                cert = NULL;
1582
0
            }
1583
0
        }
1584
0
        else if ('k' == tmpstr[0]) {
1585
0
            if (NULL != copy_nword(&tmpstr[2], filename, sizeof(filename))) {
1586
0
                snmp_log(LOG_ERR, "_cert_read_index: error parsing line %s\n",
1587
0
                    tmpstr);
1588
0
                continue;
1589
0
            }
1590
0
            key = _new_key(dirname, filename);
1591
0
            if (key && 0 == CONTAINER_INSERT(_keys, key))
1592
0
                ++count;
1593
0
            else {
1594
0
                DEBUGMSGT(("cert:index:add:key",
1595
0
                           "error inserting key into container\n"));
1596
0
                netsnmp_key_free(key);
1597
0
            }
1598
0
        }
1599
0
        else {
1600
0
            snmp_log(LOG_ERR, "unknown line in cert index for %s\n", dirname);
1601
0
            continue;
1602
0
        }
1603
0
    } /* while */
1604
0
    fclose(index);
1605
0
    SNMP_FREE(idxname);
1606
1607
0
    if (count > 0) {
1608
0
        netsnmp_iterator  *itr = CONTAINER_ITERATOR(found);
1609
0
        if (NULL == itr) {
1610
0
            snmp_log(LOG_ERR, "could not get iterator for found certs\n");
1611
0
            count = -1;
1612
0
        }
1613
0
        else {
1614
0
            cert = ITERATOR_FIRST(itr);
1615
0
            for( ; cert; cert = ITERATOR_NEXT(itr))
1616
0
                CONTAINER_INSERT(_certs, cert);
1617
0
            ITERATOR_RELEASE(itr);
1618
0
            DEBUGMSGT(("cert:index:parse","added %d certs from index\n",
1619
0
                       count));
1620
0
        }
1621
0
    }
1622
1623
0
free_cert_container:
1624
0
    if (count < 0)
1625
0
        CONTAINER_FREE_ALL(found, NULL);
1626
0
    CONTAINER_FREE(found);
1627
1628
0
    return count;
1629
0
}
1630
1631
static int
1632
_add_certdir(const char *dirname)
1633
24
{
1634
24
    FILE           *index;
1635
24
    char           *file;
1636
24
    int             count = 0;
1637
24
    netsnmp_container *cert_container;
1638
24
    netsnmp_iterator  *it;
1639
24
    struct stat     statbuf;
1640
1641
24
    netsnmp_assert(NULL != dirname);
1642
1643
24
    DEBUGMSGT(("9:cert:dir:add", " config dir: %s\n", dirname ));
1644
1645
24
    if (stat(dirname, &statbuf) != 0) {
1646
24
        DEBUGMSGT(("9:cert:dir:add", " dir not present: %s\n",
1647
24
                   dirname ));
1648
24
        return -1;
1649
24
    }
1650
0
#ifdef S_ISDIR
1651
0
    if (!S_ISDIR(statbuf.st_mode)) {
1652
0
        DEBUGMSGT(("9:cert:dir:add", " not a dir: %s\n", dirname ));
1653
0
        return -1;
1654
0
    }
1655
0
#endif
1656
1657
0
    DEBUGMSGT(("cert:index:dir", "Scanning directory %s\n", dirname));
1658
1659
    /*
1660
     * look for existing index
1661
     */
1662
0
    count = _cert_read_index(dirname, &statbuf);
1663
0
    if (count >= 0)
1664
0
        return count;
1665
1666
0
    index = _certindex_new( dirname );
1667
0
    if (NULL == index) {
1668
0
        DEBUGMSGT(("9:cert:index:dir",
1669
0
                    "error opening index for cert directory\n"));
1670
0
        DEBUGMSGTL(("cert:index", "could not open certificate index file\n"));
1671
0
    }
1672
1673
    /*
1674
     * index was missing, out of date or bad. rescan directory.
1675
     */
1676
0
    cert_container =
1677
0
        netsnmp_directory_container_read_some(NULL, dirname,
1678
0
                                              _cert_cert_filter, NULL,
1679
0
                                              NETSNMP_DIR_RELATIVE_PATH |
1680
0
                                              NETSNMP_DIR_EMPTY_OK |
1681
0
                                              NETSNMP_DIR_ALLOW_DUPLICATES);
1682
0
    if (NULL == cert_container) {
1683
0
        DEBUGMSGT(("cert:index:dir",
1684
0
                    "error creating container for cert files\n"));
1685
0
        goto err_index;
1686
0
    }
1687
1688
    /*
1689
     * iterate through the found files and add them to index
1690
     */
1691
0
    it = CONTAINER_ITERATOR(cert_container);
1692
0
    if (NULL == it) {
1693
0
        DEBUGMSGT(("cert:index:dir",
1694
0
                    "error creating iterator for cert files\n"));
1695
0
        goto err_container;
1696
0
    }
1697
1698
0
    for (file = ITERATOR_FIRST(it); file; file = ITERATOR_NEXT(it)) {
1699
0
        DEBUGMSGT(("cert:index:dir", "adding %s to index\n", file));
1700
0
        if ( 0 == _add_certfile( dirname, file, index ))
1701
0
            count++;
1702
0
        else
1703
0
            DEBUGMSGT(("cert:index:dir", "error adding %s to index\n",
1704
0
                        file));
1705
0
    }
1706
1707
    /*
1708
     * clean up and return
1709
     */
1710
0
    ITERATOR_RELEASE(it);
1711
1712
0
  err_container:
1713
0
    netsnmp_directory_container_free(cert_container);
1714
1715
0
  err_index:
1716
0
    if (index)
1717
0
        fclose(index);
1718
1719
0
    return count;
1720
0
}
1721
1722
static void
1723
_cert_indexes_load(void)
1724
2
{
1725
2
    const char     *confpath;
1726
2
    char           *confpath_copy, *dir, *st = NULL;
1727
2
    char            certdir[SNMP_MAXPATH];
1728
2
    const char     *subdirs[] = { NULL, "ca-certs", "certs", "private", NULL };
1729
2
    int             i = 0;
1730
1731
    /*
1732
     * load indexes from persistent dir
1733
     */
1734
2
    _certindexes_load();
1735
1736
    /*
1737
     * duplicate path building from read_config_files_of_type() in
1738
     * read_config.c. That is, use SNMPCONFPATH environment variable if
1739
     * it is defined, otherwise use configuration directory.
1740
     */
1741
2
    confpath = netsnmp_getenv("SNMPCONFPATH");
1742
2
    if (NULL == confpath)
1743
2
        confpath = get_configuration_directory();
1744
1745
2
    subdirs[0] = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1746
2
                                       NETSNMP_DS_LIB_CERT_EXTRA_SUBDIR);
1747
2
    confpath_copy = strdup(confpath);
1748
2
    if (!confpath_copy)
1749
0
        return;
1750
2
    for ( dir = strtok_r(confpath_copy, ENV_SEPARATOR, &st);
1751
10
          dir; dir = strtok_r(NULL, ENV_SEPARATOR, &st)) {
1752
1753
8
        i = (NULL == subdirs[0]) ? 1 : 0;
1754
32
        for ( ; subdirs[i] ; ++i ) {
1755
            /** check tls subdir */
1756
24
            snprintf(certdir, sizeof(certdir), "%s/tls/%s", dir, subdirs[i]);
1757
24
            _add_certdir(certdir);
1758
24
        } /* for subdirs */
1759
8
    } /* for conf path dirs */
1760
2
    SNMP_FREE(confpath_copy);
1761
2
}
1762
1763
static void
1764
_cert_print(void *p, void *context)
1765
0
{
1766
0
    netsnmp_cert *c = p;
1767
1768
0
    if (NULL == c)
1769
0
        return;
1770
1771
0
    DEBUGMSGT(("cert:dump", "cert %s in %s at offset %d\n", c->info.filename, c->info.dir, c->offset));
1772
0
    DEBUGMSGT(("cert:dump", "   type %d flags 0x%x (%s)\n",
1773
0
             c->info.type, c->info.allowed_uses,
1774
0
              _mode_str(c->info.allowed_uses)));
1775
0
    DEBUGIF("9:cert:dump") {
1776
0
        if (NS_CERT_TYPE_KEY != c->info.type) {
1777
0
            if(c->subject) {
1778
0
                if (c->info.allowed_uses & NS_CERT_CA)
1779
0
                    DEBUGMSGT(("9:cert:dump", "   CA: %s\n", c->subject));
1780
0
                else
1781
0
                    DEBUGMSGT(("9:cert:dump", "   subject: %s\n", c->subject));
1782
0
            }
1783
0
            if(c->issuer)
1784
0
                DEBUGMSGT(("9:cert:dump", "   issuer: %s\n", c->issuer));
1785
0
            if(c->fingerprint)
1786
0
                DEBUGMSGT(("9:cert:dump", "   fingerprint: %s(%d):%s\n",
1787
0
                           se_find_label_in_slist("cert_hash_alg", c->hash_type),
1788
0
                           c->hash_type, c->fingerprint));
1789
0
        }
1790
        /* netsnmp_feature_require(cert_utils_dump_names) */
1791
        /* netsnmp_openssl_cert_dump_names(c->ocert); */
1792
0
        netsnmp_openssl_cert_dump_extensions(c->ocert);
1793
0
    }
1794
    
1795
0
}
1796
1797
static void
1798
_key_print(void *p, void *context)
1799
0
{
1800
0
    netsnmp_key *k = p;
1801
1802
0
    if (NULL == k)
1803
0
        return;
1804
1805
0
    DEBUGMSGT(("cert:dump", "key %s in %s\n", k->info.filename, k->info.dir));
1806
0
    DEBUGMSGT(("cert:dump", "   type %d flags 0x%x (%s)\n", k->info.type,
1807
0
              k->info.allowed_uses, _mode_str(k->info.allowed_uses)));
1808
0
}
1809
1810
void
1811
netsnmp_cert_dump_all(void)
1812
1
{
1813
1
    CONTAINER_FOR_EACH(_certs, _cert_print, NULL);
1814
1
    CONTAINER_FOR_EACH(_keys, _key_print, NULL);
1815
1
}
1816
1817
#ifdef CERT_MAIN
1818
/*
1819
 * export BLD=~/net-snmp/build/ SRC=~/net-snmp/src 
1820
 * cc -DCERT_MAIN `$BLD/net-snmp-config --cflags` `$BLD/net-snmp-config --build-includes $BLD/`  $SRC/snmplib/cert_util.c   -o cert_util `$BLD/net-snmp-config --build-lib-dirs $BLD` `$BLD/net-snmp-config --libs` -lcrypto -lssl
1821
 *
1822
 */
1823
int
1824
main(int argc, char** argv)
1825
{
1826
    int          ch;
1827
    extern char *optarg;
1828
1829
    while ((ch = getopt(argc, argv, "D:fHLMx:")) != EOF)
1830
        switch(ch) {
1831
            case 'D':
1832
                debug_register_tokens(optarg);
1833
                snmp_set_do_debugging(1);
1834
                break;
1835
            default:
1836
                fprintf(stderr,"unknown option %c\n", ch);
1837
        }
1838
1839
    init_snmp("dtlsapp");
1840
1841
    netsnmp_cert_dump_all();
1842
1843
    return 0;
1844
}
1845
1846
#endif /* CERT_MAIN */
1847
1848
void
1849
netsnmp_fp_lowercase_and_strip_colon(char *fp)
1850
0
{
1851
0
    char *pos, *dest=NULL;
1852
    
1853
0
    if(!fp)
1854
0
        return;
1855
1856
    /** skip to first : */
1857
0
    for (pos = fp; *pos; ++pos ) {
1858
0
        if (':' == *pos) {
1859
0
            dest = pos;
1860
0
            break;
1861
0
        }
1862
0
        else
1863
0
            *pos = isalpha(0xFF & *pos) ? tolower(0xFF & *pos) : *pos;
1864
0
    }
1865
0
    if (!*pos)
1866
0
        return;
1867
1868
    /** copy, skipping any ':' */
1869
0
    for (++pos; *pos; ++pos) {
1870
0
        if (':' == *pos)
1871
0
            continue;
1872
0
        *dest++ = tolower(0xFF & *pos);
1873
0
    }
1874
0
    *dest = *pos; /* nul termination */
1875
0
}
1876
1877
netsnmp_cert *
1878
netsnmp_cert_find(int what, int where, void *hint)
1879
0
{
1880
0
    netsnmp_cert *result = NULL;
1881
0
    char         *fp, *hint_str;
1882
1883
0
    DEBUGMSGT(("cert:find:params", "looking for %s(%d) in %s(0x%x), hint %p\n",
1884
0
               _mode_str(what), what, _where_str(where), where, hint));
1885
1886
0
    if (NS_CERTKEY_DEFAULT == where) {
1887
            
1888
0
        switch (what) {
1889
0
            case NS_CERT_IDENTITY: /* want my ID */
1890
0
                fp =
1891
0
                    netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1892
0
                                          NETSNMP_DS_LIB_TLS_LOCAL_CERT);
1893
                /** temp backwards compability; remove in 5.7 */
1894
0
                if (!fp) {
1895
0
                    int           tmp;
1896
0
                    tmp = (ptrdiff_t)hint;
1897
0
                    DEBUGMSGT(("cert:find:params", " hint = %s\n",
1898
0
                               tmp ? "server" : "client"));
1899
0
                    fp =
1900
0
                        netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, tmp ?
1901
0
                                              NETSNMP_DS_LIB_X509_SERVER_PUB :
1902
0
                                              NETSNMP_DS_LIB_X509_CLIENT_PUB );
1903
0
                }
1904
0
                if (!fp) {
1905
                    /* As a special case, use the application type to
1906
                       determine a file name to pull the default identity
1907
                       from. */
1908
0
                    return netsnmp_cert_find(what, NS_CERTKEY_FILE, netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE));
1909
0
                }
1910
0
                break;
1911
0
            case NS_CERT_REMOTE_PEER:
1912
0
                fp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1913
0
                                           NETSNMP_DS_LIB_TLS_PEER_CERT);
1914
                /** temp backwards compability; remove in 5.7 */
1915
0
                if (!fp)
1916
0
                    fp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
1917
0
                                               NETSNMP_DS_LIB_X509_SERVER_PUB);
1918
0
                break;
1919
0
            default:
1920
0
                DEBUGMSGT(("cert:find:err", "unhandled type %d for %s(%d)\n",
1921
0
                           what, _where_str(where), where));
1922
0
                return NULL;
1923
0
        }
1924
0
        if (fp)
1925
0
            return netsnmp_cert_find(what, NS_CERTKEY_MULTIPLE, fp);
1926
0
        return NULL;
1927
0
    } /* where = ds store */
1928
0
    else if (NS_CERTKEY_MULTIPLE == where) {
1929
        /* tries multiple sources of certificates based on ascii lookup keys */
1930
1931
        /* Try a fingerprint match first, which should always be done first */
1932
        /* (to avoid people naming filenames with conflicting FPs) */
1933
0
        result = netsnmp_cert_find(what, NS_CERTKEY_FINGERPRINT, hint);
1934
0
        if (!result) {
1935
            /* Then try a file name lookup */
1936
0
            result = netsnmp_cert_find(what, NS_CERTKEY_FILE, hint);
1937
0
        }
1938
0
    }
1939
0
    else if (NS_CERTKEY_FINGERPRINT == where) {
1940
0
        DEBUGMSGT(("cert:find:params", " hint = %s\n", (char *)hint));
1941
0
        result = _cert_find_fp((char *)hint);
1942
0
    }
1943
0
    else if (NS_CERTKEY_TARGET_PARAM == where) {
1944
0
        if (what != NS_CERT_IDENTITY) {
1945
0
            snmp_log(LOG_ERR, "only identity is valid for target params\n");
1946
0
            return NULL;
1947
0
        }
1948
        /** hint == target mib data */
1949
0
        hint_str = (char *)hint;
1950
0
        fp = _find_tlstmParams_fingerprint(hint_str);
1951
0
        if (NULL != fp)
1952
0
            result = _cert_find_fp(fp);
1953
1954
0
    }
1955
0
    else if (NS_CERTKEY_TARGET_ADDR == where) {
1956
        
1957
        /** hint == target mib data */
1958
0
        if (what != NS_CERT_REMOTE_PEER) {
1959
0
            snmp_log(LOG_ERR, "only peer is valid for target addr\n");
1960
0
            return NULL;
1961
0
        }
1962
        /** hint == target mib data */
1963
0
        hint_str = (char *)hint;
1964
0
        fp = _find_tlstmAddr_fingerprint(hint_str);
1965
0
        if (NULL != fp)
1966
0
            result = _cert_find_fp(fp);
1967
1968
0
    }
1969
0
    else if (NS_CERTKEY_FILE == where) {
1970
        /** hint == filename */
1971
0
        char               *filename = (char*)hint;
1972
0
        netsnmp_void_array *matching;
1973
1974
0
        DEBUGMSGT(("cert:find:params", " hint = %s\n", (char *)hint));
1975
0
        matching = _cert_reduce_subset_what(_cert_find_subset_fn(
1976
0
                                            filename, NULL ), what);
1977
0
        if (!matching)
1978
0
            return NULL;
1979
0
        if (1 == matching->size)
1980
0
            result = (netsnmp_cert*)matching->array[0];
1981
0
        else {
1982
0
            DEBUGMSGT(("cert:find:err", "%s matches multiple certs\n",
1983
0
                       filename));
1984
0
            result = NULL;
1985
0
        }
1986
0
        free(matching->array);
1987
0
        free(matching);
1988
0
    } /* where = NS_CERTKEY_FILE */
1989
0
    else { /* unknown location */
1990
        
1991
0
        DEBUGMSGT(("cert:find:err", "unhandled location %d for %d\n", where,
1992
0
                   what));
1993
0
        return NULL;
1994
0
    }
1995
    
1996
0
    if (NULL == result)
1997
0
        return NULL;
1998
1999
    /** make sure result found can be used for specified type */
2000
0
    if (!(result->info.allowed_uses & what)) {
2001
0
        DEBUGMSGT(("cert:find:err",
2002
0
                   "cert %s / %s not allowed for %s(%d) (uses=%s (%d))\n",
2003
0
                   result->info.filename, result->fingerprint, _mode_str(what),
2004
0
                   what , _mode_str(result->info.allowed_uses),
2005
0
                   result->info.allowed_uses));
2006
0
        return NULL;
2007
0
    }
2008
    
2009
    /** make sure we have the cert data */
2010
0
    if (netsnmp_cert_load_x509(result) == CERT_LOAD_ERR)
2011
0
        return NULL;
2012
2013
0
    DEBUGMSGT(("cert:find:found",
2014
0
               "using cert %s / %s for %s(%d) (uses=%s (%d))\n",
2015
0
               result->info.filename, result->fingerprint, _mode_str(what),
2016
0
               what , _mode_str(result->info.allowed_uses),
2017
0
               result->info.allowed_uses));
2018
            
2019
0
    return result;
2020
0
}
2021
2022
netsnmp_void_array *
2023
netsnmp_certs_find(int what, int where, void *hint)
2024
0
{
2025
2026
0
    DEBUGMSGT(("certs:find:params", "looking for %s(%d) in %s(0x%x), hint %p\n",
2027
0
               _mode_str(what), what, _where_str(where), where, hint));
2028
2029
0
    if (NS_CERTKEY_FILE == where) {
2030
        /** hint == filename */
2031
0
        char               *filename = (char*)hint;
2032
0
        netsnmp_void_array *matching;
2033
2034
0
        DEBUGMSGT(("cert:find:params", " hint = %s\n", (char *)hint));
2035
0
        matching = _cert_reduce_subset_what(_cert_find_subset_fn(
2036
0
                                            filename, NULL ), what);
2037
2038
0
        return matching;
2039
0
    } /* where = NS_CERTKEY_FILE */
2040
0
    else { /* unknown location */
2041
2042
0
        DEBUGMSGT(("certs:find:err", "unhandled location %d for %d\n", where,
2043
0
                   what));
2044
0
        return NULL;
2045
0
    }
2046
0
}
2047
2048
#ifndef NETSNMP_FEATURE_REMOVE_CERT_FINGERPRINTS
2049
int
2050
netsnmp_cert_check_vb_fingerprint(const netsnmp_variable_list *var)
2051
0
{
2052
0
    if (!var)
2053
0
        return SNMP_ERR_GENERR;
2054
2055
0
    if (0 == var->val_len) /* empty allowed in some cases */
2056
0
        return SNMP_ERR_NOERROR;
2057
2058
0
    if (! (0x01 & var->val_len)) { /* odd len */
2059
0
        DEBUGMSGT(("cert:varbind:fingerprint",
2060
0
                   "expecting odd length for fingerprint\n"));
2061
0
        return SNMP_ERR_WRONGLENGTH;
2062
0
    }
2063
2064
0
    if (var->val.string[0] > NS_HASH_MAX) {
2065
0
        DEBUGMSGT(("cert:varbind:fingerprint", "hashtype %d > max %d\n",
2066
0
                   var->val.string[0], NS_HASH_MAX));
2067
0
        return SNMP_ERR_WRONGVALUE;
2068
0
    }
2069
2070
0
    return SNMP_ERR_NOERROR;
2071
0
}
2072
2073
/**
2074
 * break a SnmpTLSFingerprint into an integer hash type + hex string
2075
 *
2076
 * @return SNMPERR_SUCCESS : on success
2077
 * @return SNMPERR_GENERR  : on failure
2078
 */
2079
int
2080
netsnmp_tls_fingerprint_parse(const u_char *binary_fp, int fp_len,
2081
                              char **fp_str_ptr, u_int *fp_str_len, int realloc,
2082
                              u_char *hash_type_ptr)
2083
0
{
2084
0
    int     needed;
2085
0
    size_t  fp_str_size;
2086
2087
0
    netsnmp_require_ptr_LRV( hash_type_ptr, SNMPERR_GENERR );
2088
0
    netsnmp_require_ptr_LRV( fp_str_ptr, SNMPERR_GENERR );
2089
0
    netsnmp_require_ptr_LRV( fp_str_len, SNMPERR_GENERR );
2090
2091
    /*
2092
     * output string is binary fp length (minus 1 for initial hash type 
2093
     * char) * 2 for bin to hex conversion, + 1 for null termination.
2094
     */
2095
0
    needed = ((fp_len - 1) * 2) + 1;
2096
0
    if (*fp_str_len < needed) {
2097
0
        DEBUGMSGT(("tls:fp:parse", "need %d bytes for output\n", needed ));
2098
0
        return SNMPERR_GENERR;
2099
0
    }
2100
2101
    /*
2102
     * make sure hash type is in valid range
2103
     */
2104
0
    if ((0 == binary_fp[0]) || (binary_fp[0] > NS_HASH_MAX)) {
2105
0
        DEBUGMSGT(("tls:fp:parse", "invalid hash type %d\n",
2106
0
                   binary_fp[0]));
2107
0
        return SNMPERR_GENERR;
2108
0
    }
2109
2110
    /*
2111
     * netsnmp_binary_to_hex allocate space for string, if needed
2112
     */
2113
0
    fp_str_size = *fp_str_len;
2114
0
    *hash_type_ptr = binary_fp[0];
2115
0
    netsnmp_binary_to_hex((u_char**)fp_str_ptr, &fp_str_size,
2116
0
                          realloc, &binary_fp[1], fp_len - 1);
2117
0
    *fp_str_len = fp_str_size;
2118
0
    if (0 == *fp_str_len)
2119
0
        return SNMPERR_GENERR;
2120
2121
0
    return SNMPERR_SUCCESS;
2122
0
}
2123
#endif /* NETSNMP_FEATURE_REMOVE_CERT_FINGERPRINTS */
2124
2125
#ifndef NETSNMP_FEATURE_REMOVE_TLS_FINGERPRINT_BUILD
2126
/**
2127
 * combine a hash type and hex fingerprint into a SnmpTLSFingerprint
2128
 *
2129
 * On entry, tls_fp_len should point to the size of the tls_fp buffer.
2130
 * On a successful exit, tls_fp_len will contain the length of the
2131
 * fingerprint buffer.
2132
 */
2133
int
2134
netsnmp_tls_fingerprint_build(int hash_type, const char *hex_fp,
2135
                                   u_char **tls_fp, size_t *tls_fp_len,
2136
                                   int realloc)
2137
0
{
2138
0
    int     hex_fp_len, rc;
2139
0
    size_t  tls_fp_size = *tls_fp_len;
2140
0
    size_t  offset;
2141
2142
0
    netsnmp_require_ptr_LRV( hex_fp, SNMPERR_GENERR );
2143
0
    netsnmp_require_ptr_LRV( tls_fp, SNMPERR_GENERR );
2144
0
    netsnmp_require_ptr_LRV( tls_fp_len, SNMPERR_GENERR );
2145
2146
0
    hex_fp_len = strlen(hex_fp);
2147
0
    if (0 == hex_fp_len) {
2148
0
        *tls_fp_len = 0;
2149
0
        return SNMPERR_SUCCESS;
2150
0
    }
2151
2152
0
    if ((hash_type <= NS_HASH_NONE) || (hash_type > NS_HASH_MAX)) {
2153
0
        DEBUGMSGT(("tls:fp:build", "invalid hash type %d\n", hash_type ));
2154
0
        return SNMPERR_GENERR;
2155
0
    }
2156
2157
    /*
2158
     * convert to binary
2159
     */
2160
0
    offset = 1;
2161
0
    rc = netsnmp_hex_to_binary(tls_fp, &tls_fp_size, &offset, realloc, hex_fp,
2162
0
                               ":");
2163
0
    *tls_fp_len = tls_fp_size;
2164
0
    if (rc != 1)
2165
0
        return SNMPERR_GENERR;
2166
0
    *tls_fp_len = offset;
2167
0
    (*tls_fp)[0] = hash_type;
2168
                               
2169
0
    return SNMPERR_SUCCESS;
2170
0
}
2171
#endif /* NETSNMP_FEATURE_REMOVE_TLS_FINGERPRINT_BUILD */
2172
2173
/**
2174
 * Trusts a given certificate for use in TLS translations.
2175
 *
2176
 * @param ctx The SSL context to trust the certificate in
2177
 * @param thiscert The netsnmp_cert certificate to trust
2178
 *
2179
 * @return SNMPERR_SUCCESS : on success
2180
 * @return SNMPERR_GENERR  : on failure
2181
 */
2182
int
2183
netsnmp_cert_trust(SSL_CTX *ctx, netsnmp_cert *thiscert)
2184
0
{
2185
0
    X509_STORE     *certstore;
2186
0
    X509           *cert;
2187
0
    char           *fingerprint;
2188
2189
    /* ensure all needed pieces are present */
2190
0
    netsnmp_assert_or_msgreturn(NULL != thiscert, "NULL certificate passed in",
2191
0
                                SNMPERR_GENERR);
2192
0
    netsnmp_assert_or_msgreturn(NULL != thiscert->info.dir,
2193
0
                                "NULL certificate directory name passed in",
2194
0
                                SNMPERR_GENERR);
2195
0
    netsnmp_assert_or_msgreturn(NULL != thiscert->info.filename,
2196
0
                                "NULL certificate filename name passed in",
2197
0
                                SNMPERR_GENERR);
2198
2199
    /* get the trusted certificate store and the certificate to load into it */
2200
0
    certstore = SSL_CTX_get_cert_store(ctx);
2201
0
    netsnmp_assert_or_msgreturn(NULL != certstore,
2202
0
                                "failed to get certificate trust store",
2203
0
                                SNMPERR_GENERR);
2204
0
    cert = netsnmp_ocert_get(thiscert);
2205
0
    netsnmp_assert_or_msgreturn(NULL != cert,
2206
0
                                "failed to get certificate from netsnmp_cert",
2207
0
                                SNMPERR_GENERR);
2208
2209
    /* Put the certificate into the store */
2210
0
    fingerprint = netsnmp_openssl_cert_get_fingerprint(cert, NS_HASH_SHA1);
2211
0
    DEBUGMSGTL(("cert:trust",
2212
0
                "putting trusted cert %p = %s in certstore %p\n", cert,
2213
0
                fingerprint, certstore));
2214
0
    SNMP_FREE(fingerprint);
2215
0
    X509_STORE_add_cert(certstore, cert);
2216
2217
0
    return SNMPERR_SUCCESS;
2218
0
}
2219
2220
/**
2221
 * Trusts a given certificate's root CA for use in TLS translations.
2222
 * If no issuer is found the existing certificate will be trusted instead.
2223
 *
2224
 * @param ctx The SSL context to trust the certificate in
2225
 * @param thiscert The netsnmp_cert certificate 
2226
 *
2227
 * @return SNMPERR_SUCCESS : on success
2228
 * @return SNMPERR_GENERR  : on failure
2229
 */
2230
int
2231
netsnmp_cert_trust_ca(SSL_CTX *ctx, netsnmp_cert *thiscert)
2232
0
{
2233
0
    netsnmp_assert_or_msgreturn(NULL != thiscert, "NULL certificate passed in",
2234
0
                                SNMPERR_GENERR);
2235
2236
    /* find the root CA certificate in the chain */
2237
0
    DEBUGMSGTL(("cert:trust_ca", "checking roots for %p \n", thiscert));
2238
0
    while (thiscert->issuer_cert) {
2239
0
        thiscert = thiscert->issuer_cert;
2240
0
        DEBUGMSGTL(("cert:trust_ca", "  up one to %p\n", thiscert));
2241
0
    }
2242
2243
    /* Add the found top level certificate to the store */
2244
0
    return netsnmp_cert_trust(ctx, thiscert);
2245
0
}
2246
2247
netsnmp_container *
2248
netsnmp_cert_get_trustlist(void)
2249
0
{
2250
0
    if (!_trusted_certs)
2251
0
        _setup_trusted_certs();
2252
0
    return _trusted_certs;
2253
0
}
2254
2255
static void
2256
_parse_trustcert(const char *token, char *line)
2257
0
{
2258
0
    if (!_trusted_certs)
2259
0
        _setup_trusted_certs();
2260
2261
0
    if (!_trusted_certs)
2262
0
        return;
2263
2264
0
    CONTAINER_INSERT(_trusted_certs, strdup(line));
2265
0
}
2266
2267
/* ***************************************************************************
2268
 *
2269
 * mode text functions
2270
 *
2271
 */
2272
static const char *_mode_str(u_char mode)
2273
0
{
2274
0
    return _modes[mode];
2275
0
}
2276
2277
static const char *_where_str(u_int what)
2278
0
{
2279
0
    switch (what) {
2280
0
        case NS_CERTKEY_DEFAULT: return "DEFAULT";
2281
0
        case NS_CERTKEY_FILE: return "FILE";
2282
0
        case NS_CERTKEY_FINGERPRINT: return "FINGERPRINT";
2283
0
        case NS_CERTKEY_MULTIPLE: return "MULTIPLE";
2284
0
        case NS_CERTKEY_CA: return "CA";
2285
0
        case NS_CERTKEY_SAN_RFC822: return "SAN_RFC822";
2286
0
        case NS_CERTKEY_SAN_DNS: return "SAN_DNS";
2287
0
        case NS_CERTKEY_SAN_IPADDR: return "SAN_IPADDR";
2288
0
        case NS_CERTKEY_COMMON_NAME: return "COMMON_NAME";
2289
0
        case NS_CERTKEY_TARGET_PARAM: return "TARGET_PARAM";
2290
0
        case NS_CERTKEY_TARGET_ADDR: return "TARGET_ADDR";
2291
0
    }
2292
2293
0
    return "UNKNOWN";
2294
0
}
2295
2296
/* ***************************************************************************
2297
 *
2298
 * find functions
2299
 *
2300
 */
2301
static netsnmp_cert *
2302
_cert_find_fp(const char *fingerprint)
2303
0
{
2304
0
    netsnmp_cert cert, *result = NULL;
2305
0
    char         fp[EVP_MAX_MD_SIZE*3];
2306
2307
0
    if (NULL == fingerprint)
2308
0
        return NULL;
2309
2310
0
    strlcpy(fp, fingerprint, sizeof(fp));
2311
0
    netsnmp_fp_lowercase_and_strip_colon(fp);
2312
2313
    /** clear search key */
2314
0
    memset(&cert, 0x00, sizeof(cert));
2315
2316
0
    cert.fingerprint = fp;
2317
2318
0
    result = CONTAINER_FIND(_certs,&cert);
2319
0
    return result;
2320
0
}
2321
2322
/*
2323
 * reduce subset by eliminating any filenames that are longer than
2324
 * the specified file name. e.g. 'snmp' would match 'snmp.key' and
2325
 * 'snmpd.key'. We only want 'snmp.X', where X is a valid extension.
2326
 */
2327
static void
2328
_reduce_subset(netsnmp_void_array *matching, const char *filename)
2329
0
{
2330
0
    netsnmp_cert_common *cc;
2331
0
    int i = 0, j, newsize, pos;
2332
2333
0
    if ((NULL == matching) || (NULL == filename))
2334
0
        return;
2335
2336
0
    pos = strlen(filename);
2337
0
    newsize = matching->size;
2338
2339
0
    for( ; i < matching->size; ) {
2340
        /*
2341
         * if we've shifted matches down we'll hit a NULL entry before
2342
         * we hit the end of the array.
2343
         */
2344
0
        if (NULL == matching->array[i])
2345
0
            break;
2346
        /*
2347
         * skip over valid matches. Note that we do not want to use
2348
         * _type_from_filename.
2349
         */
2350
0
        cc = (netsnmp_cert_common*)matching->array[i];
2351
0
        if (('.' == cc->filename[pos]) &&
2352
0
            (NS_CERT_TYPE_UNKNOWN != _cert_ext_type(&cc->filename[pos+1]))) {
2353
0
            ++i;
2354
0
            continue;
2355
0
        }
2356
        /*
2357
         * shrink array by shifting everything down a spot. Might not be
2358
         * the most efficient solution, but this is just happening at
2359
         * startup and hopefully most certs won't have common prefixes.
2360
         */
2361
0
        --newsize;
2362
0
        for ( j=i; j < newsize; ++j )
2363
0
            matching->array[j] = matching->array[j+1];
2364
0
        matching->array[j] = NULL;
2365
        /** no ++i; just shifted down, need to look at same position again */
2366
0
    }
2367
    /*
2368
     * if we shifted, set the new size
2369
     */
2370
0
    if (newsize != matching->size) {
2371
0
        DEBUGMSGT(("9:cert:subset:reduce", "shrank from %" NETSNMP_PRIz "d to %d\n",
2372
0
                   matching->size, newsize));
2373
0
        matching->size = newsize;
2374
0
    }
2375
0
}
2376
2377
/*
2378
 * reduce subset by eliminating any filenames that are not under the
2379
 * specified directory path.
2380
 */
2381
static void
2382
_reduce_subset_dir(netsnmp_void_array *matching, const char *directory)
2383
0
{
2384
0
    netsnmp_cert_common *cc;
2385
0
    int                  i = 0, j, newsize, dir_len;
2386
0
    char                 dir[SNMP_MAXPATH], *pos;
2387
2388
0
    if ((NULL == matching) || (NULL == directory))
2389
0
        return;
2390
2391
0
    newsize = matching->size;
2392
2393
    /*
2394
     * dir struct should be something like
2395
     *          /usr/share/snmp/tls/certs
2396
     *          /usr/share/snmp/tls/private
2397
     *
2398
     * so we want to backup up on directory for compares..
2399
     */
2400
0
    strlcpy(dir, directory, sizeof(dir));
2401
0
    pos = strrchr(dir, '/');
2402
0
    if (NULL == pos) {
2403
0
        DEBUGMSGTL(("cert:subset:dir", "no '/' in directory %s\n", directory));
2404
0
        return;
2405
0
    }
2406
0
    *pos = '\0';
2407
0
    dir_len = strlen(dir);
2408
2409
0
    for( ; i < matching->size; ) {
2410
        /*
2411
         * if we've shifted matches down we'll hit a NULL entry before
2412
         * we hit the end of the array.
2413
         */
2414
0
        if (NULL == matching->array[i])
2415
0
            break;
2416
        /*
2417
         * skip over valid matches. 
2418
         */
2419
0
        cc = (netsnmp_cert_common*)matching->array[i];
2420
0
        if (strncmp(dir, cc->dir, dir_len) == 0) {
2421
0
            ++i;
2422
0
            continue;
2423
0
        }
2424
        /*
2425
         * shrink array by shifting everything down a spot. Might not be
2426
         * the most efficient solution, but this is just happening at
2427
         * startup and hopefully most certs won't have common prefixes.
2428
         */
2429
0
        --newsize;
2430
0
        for ( j=i; j < newsize; ++j )
2431
0
            matching->array[j] = matching->array[j+1];
2432
0
        matching->array[j] = NULL;
2433
        /** no ++i; just shifted down, need to look at same position again */
2434
0
    }
2435
    /*
2436
     * if we shifted, set the new size
2437
     */
2438
0
    if (newsize != matching->size) {
2439
0
        DEBUGMSGT(("9:cert:subset:dir", "shrank from %" NETSNMP_PRIz "d to %d\n",
2440
0
                   matching->size, newsize));
2441
0
        matching->size = newsize;
2442
0
    }
2443
0
}
2444
2445
/*
2446
 * reduce subset by eliminating any certificates that are not the
2447
 * first certificate in a file. This allows us to ignore certificate
2448
 * chains when testing for specific certificates, and to match keys
2449
 * to the first certificate only.
2450
 */
2451
static netsnmp_void_array *
2452
_cert_reduce_subset_first(netsnmp_void_array *matching)
2453
0
{
2454
0
    netsnmp_cert *cc;
2455
0
    int i = 0, j, newsize;
2456
2457
0
    if ((NULL == matching))
2458
0
        return matching;
2459
2460
0
    newsize = matching->size;
2461
2462
0
    for( ; i < matching->size; ) {
2463
        /*
2464
         * if we've shifted matches down we'll hit a NULL entry before
2465
         * we hit the end of the array.
2466
         */
2467
0
        if (NULL == matching->array[i])
2468
0
            break;
2469
        /*
2470
         * skip over valid matches. The first entry has an offset of zero.
2471
         */
2472
0
        cc = (netsnmp_cert*)matching->array[i];
2473
0
        if (0 == cc->offset) {
2474
0
            ++i;
2475
0
            continue;
2476
0
        }
2477
        /*
2478
         * shrink array by shifting everything down a spot. Might not be
2479
         * the most efficient solution, but this is just happening at
2480
         * startup and hopefully most certs won't have common prefixes.
2481
         */
2482
0
        --newsize;
2483
0
        for ( j=i; j < newsize; ++j )
2484
0
            matching->array[j] = matching->array[j+1];
2485
0
        matching->array[j] = NULL;
2486
        /** no ++i; just shifted down, need to look at same position again */
2487
0
    }
2488
    /*
2489
     * if we shifted, set the new size
2490
     */
2491
0
    if (newsize != matching->size) {
2492
0
        DEBUGMSGT(("9:cert:subset:first", "shrank from %" NETSNMP_PRIz "d to %d\n",
2493
0
                   matching->size, newsize));
2494
0
        matching->size = newsize;
2495
0
    }
2496
2497
0
    if (0 == matching->size) {
2498
0
        free(matching->array);
2499
0
        SNMP_FREE(matching);
2500
0
    }
2501
2502
0
    return matching;
2503
0
}
2504
2505
/*
2506
 * reduce subset by eliminating any certificates that do not match
2507
 * purpose specified.
2508
 */
2509
static netsnmp_void_array *
2510
_cert_reduce_subset_what(netsnmp_void_array *matching, int what)
2511
0
{
2512
0
    netsnmp_cert_common *cc;
2513
0
    int i = 0, j, newsize;
2514
2515
0
    if ((NULL == matching))
2516
0
        return matching;
2517
2518
0
    newsize = matching->size;
2519
2520
0
    for( ; i < matching->size; ) {
2521
        /*
2522
         * if we've shifted matches down we'll hit a NULL entry before
2523
         * we hit the end of the array.
2524
         */
2525
0
        if (NULL == matching->array[i])
2526
0
            break;
2527
        /*
2528
         * skip over valid matches. The first entry has an offset of zero.
2529
         */
2530
0
        cc = (netsnmp_cert_common *)matching->array[i];
2531
0
        if ((cc->allowed_uses & what)) {
2532
0
            ++i;
2533
0
            continue;
2534
0
        }
2535
        /*
2536
         * shrink array by shifting everything down a spot. Might not be
2537
         * the most efficient solution, but this is just happening at
2538
         * startup and hopefully most certs won't have common prefixes.
2539
         */
2540
0
        --newsize;
2541
0
        for ( j=i; j < newsize; ++j )
2542
0
            matching->array[j] = matching->array[j+1];
2543
0
        matching->array[j] = NULL;
2544
        /** no ++i; just shifted down, need to look at same position again */
2545
0
    }
2546
    /*
2547
     * if we shifted, set the new size
2548
     */
2549
0
    if (newsize != matching->size) {
2550
0
        DEBUGMSGT(("9:cert:subset:what", "shrank from %" NETSNMP_PRIz "d to %d\n",
2551
0
                   matching->size, newsize));
2552
0
        matching->size = newsize;
2553
0
    }
2554
2555
0
    if (0 == matching->size) {
2556
0
        free(matching->array);
2557
0
        SNMP_FREE(matching);
2558
0
    }
2559
2560
0
    return matching;
2561
0
}
2562
2563
static netsnmp_void_array *
2564
_cert_find_subset_common(const char *filename, netsnmp_container *container)
2565
0
{
2566
0
    netsnmp_cert_common   search;
2567
0
    netsnmp_void_array   *matching;
2568
2569
0
    netsnmp_assert(filename && container);
2570
2571
0
    memset(&search, 0x00, sizeof(search));    /* clear search key */
2572
2573
0
    search.filename = NETSNMP_REMOVE_CONST(char*,filename);
2574
2575
0
    matching = CONTAINER_GET_SUBSET(container, &search);
2576
0
    DEBUGMSGT(("9:cert:subset:found", "%" NETSNMP_PRIz "d matches\n", matching ?
2577
0
               matching->size : 0));
2578
0
    if (matching && matching->size > 1) {
2579
0
        _reduce_subset(matching, filename);
2580
0
        if (0 == matching->size) {
2581
0
            free(matching->array);
2582
0
            SNMP_FREE(matching);
2583
0
        }
2584
0
    }
2585
0
    return matching;
2586
0
}
2587
2588
static netsnmp_void_array *
2589
_cert_find_subset_fn(const char *filename, const char *directory)
2590
0
{
2591
0
    netsnmp_container    *fn_container;
2592
0
    netsnmp_void_array   *matching;
2593
2594
    /** find subcontainer with filename as key */
2595
0
    fn_container = SUBCONTAINER_FIND(_certs, "certs_fn");
2596
0
    netsnmp_assert(fn_container);
2597
2598
0
    matching = _cert_find_subset_common(filename, fn_container);
2599
0
    if (matching && (matching->size > 1) && directory) {
2600
0
        _reduce_subset_dir(matching, directory);
2601
0
        if (0 == matching->size) {
2602
0
            free(matching->array);
2603
0
            SNMP_FREE(matching);
2604
0
        }
2605
0
    }
2606
0
    return matching;
2607
0
}
2608
2609
static netsnmp_void_array *
2610
_cert_find_subset_sn(const char *subject)
2611
0
{
2612
0
    netsnmp_cert          search;
2613
0
    netsnmp_void_array   *matching;
2614
0
    netsnmp_container    *sn_container;
2615
2616
    /** find subcontainer with subject as key */
2617
0
    sn_container = SUBCONTAINER_FIND(_certs, "certs_sn");
2618
0
    netsnmp_assert(sn_container);
2619
2620
0
    memset(&search, 0x00, sizeof(search));    /* clear search key */
2621
2622
0
    search.subject = NETSNMP_REMOVE_CONST(char*,subject);
2623
2624
0
    matching = CONTAINER_GET_SUBSET(sn_container, &search);
2625
0
    DEBUGMSGT(("9:cert:subset:found", "%" NETSNMP_PRIz "d matches\n", matching ?
2626
0
               matching->size : 0));
2627
0
    return matching;
2628
0
}
2629
2630
static netsnmp_void_array *
2631
_key_find_subset(const char *filename)
2632
0
{
2633
0
    return _cert_find_subset_common(filename, _keys);
2634
0
}
2635
2636
/** find all entries matching given fingerprint */
2637
static netsnmp_void_array *
2638
_find_subset_fp(netsnmp_container *certs, const char *fp)
2639
0
{
2640
0
    netsnmp_cert_map    entry;
2641
0
    netsnmp_container  *fp_container;
2642
0
    netsnmp_void_array *va;
2643
2644
0
    if ((NULL == certs) || (NULL == fp))
2645
0
        return NULL;
2646
2647
0
    fp_container = SUBCONTAINER_FIND(certs, "cert2sn_fp");
2648
0
    netsnmp_assert_or_msgreturn(fp_container, "cert2sn_fp container missing",
2649
0
                                NULL);
2650
2651
0
    memset(&entry, 0x0, sizeof(entry));
2652
2653
0
    entry.fingerprint = NETSNMP_REMOVE_CONST(char*,fp);
2654
2655
0
    va = CONTAINER_GET_SUBSET(fp_container, &entry);
2656
0
    return va;
2657
0
}
2658
2659
#if 0  /* not used yet */
2660
static netsnmp_key *
2661
_key_find_fn(const char *filename)
2662
{
2663
    netsnmp_key key, *result = NULL;
2664
2665
    netsnmp_assert(NULL != filename);
2666
2667
    memset(&key, 0x00, sizeof(key));    /* clear search key */
2668
    key.info.filename = NETSNMP_REMOVE_CONST(char*,filename);
2669
    result = CONTAINER_FIND(_keys,&key);
2670
    return result;
2671
}
2672
#endif
2673
2674
static int
2675
_time_filter(const void *text, void *ctx)
2676
0
{
2677
0
    const netsnmp_file *f = text;
2678
0
    struct stat *idx = ctx;
2679
2680
    /** include if mtime or ctime newer than index mtime */
2681
0
    if (f && idx && f->stats &&
2682
0
        ((f->stats->st_mtime >= idx->st_mtime) ||
2683
0
         (f->stats->st_ctime >= idx->st_mtime)))
2684
0
        return NETSNMP_DIR_INCLUDE;
2685
2686
0
    return NETSNMP_DIR_EXCLUDE;
2687
0
}
2688
2689
/* ***************************************************************************
2690
 * ***************************************************************************
2691
 *
2692
 *
2693
 * cert map functions
2694
 *
2695
 *
2696
 * ***************************************************************************
2697
 * ***************************************************************************/
2698
5.59k
#define MAP_CONFIG_TOKEN "certSecName"
2699
static void _parse_map(const char *token, char *line);
2700
static void _map_free(void *map, void *ctx);
2701
static void _purge_config_entries(void);
2702
2703
static void
2704
_init_tlstmCertToTSN(void)
2705
2.79k
{
2706
2.79k
    const char *certSecName_help = MAP_CONFIG_TOKEN " PRIORITY FINGERPRINT "
2707
2.79k
        "[--shaNN|md5] <--sn SECNAME | --rfc822 | --dns | --ip | --cn | --any>";
2708
2709
    /*
2710
     * container for cert to fingerprint mapping, with fingerprint key
2711
     */
2712
2.79k
    _maps = netsnmp_cert_map_container_create(1);
2713
2714
2.79k
    register_config_handler(NULL, MAP_CONFIG_TOKEN, _parse_map, _purge_config_entries,
2715
2.79k
                            certSecName_help);
2716
2.79k
}
2717
2718
netsnmp_cert_map *
2719
netsnmp_cert_map_alloc(char *fingerprint, X509 *ocert)
2720
0
{
2721
0
    netsnmp_cert_map *cert_map = SNMP_MALLOC_TYPEDEF(netsnmp_cert_map);
2722
0
    if (NULL == cert_map) {
2723
0
        snmp_log(LOG_ERR, "could not allocate netsnmp_cert_map\n");
2724
0
        return NULL;
2725
0
    }
2726
    
2727
0
    if (fingerprint) {
2728
        /** MIB limits to 255 bytes; 2x since we've got ascii */
2729
0
        if (strlen(fingerprint) > (SNMPADMINLENGTH * 2)) {
2730
0
            snmp_log(LOG_ERR, "fingerprint %s exceeds max length %d\n",
2731
0
                     fingerprint, (SNMPADMINLENGTH * 2));
2732
0
            free(cert_map);
2733
0
            return NULL;
2734
0
        }
2735
0
        cert_map->fingerprint = strdup(fingerprint);
2736
0
    }
2737
0
    if (ocert) {
2738
0
        cert_map->hashType = netsnmp_openssl_cert_get_hash_type(ocert);
2739
0
        cert_map->ocert = ocert;
2740
0
    }
2741
2742
0
    return cert_map;
2743
0
}
2744
2745
void
2746
netsnmp_cert_map_free(netsnmp_cert_map *cert_map)
2747
0
{
2748
0
    if (NULL == cert_map)
2749
0
        return;
2750
2751
0
    SNMP_FREE(cert_map->fingerprint);
2752
0
    SNMP_FREE(cert_map->data);
2753
    /** x509 cert isn't ours */
2754
0
    free(cert_map); /* SNMP_FREE wasted on param */
2755
0
}
2756
2757
int
2758
netsnmp_cert_map_add(netsnmp_cert_map *map)
2759
0
{
2760
0
    int                rc;
2761
2762
0
    if (NULL == map)
2763
0
        return -1;
2764
2765
0
    DEBUGMSGTL(("cert:map:add", "pri %d, fp %s\n",
2766
0
                map->priority, map->fingerprint));
2767
2768
0
    if ((rc = CONTAINER_INSERT(_maps, map)) != 0)
2769
0
        snmp_log(LOG_ERR, "could not insert new certificate map");
2770
2771
0
    return rc;
2772
0
}
2773
2774
#ifndef NETSNMP_FEATURE_REMOVE_CERT_MAP_REMOVE
2775
int
2776
netsnmp_cert_map_remove(netsnmp_cert_map *map)
2777
0
{
2778
0
    int                rc;
2779
2780
0
    if (NULL == map)
2781
0
        return -1;
2782
2783
0
    DEBUGMSGTL(("cert:map:remove", "pri %d, fp %s\n",
2784
0
                map->priority, map->fingerprint));
2785
2786
0
    if ((rc = CONTAINER_REMOVE(_maps, map)) != 0)
2787
0
        snmp_log(LOG_ERR, "could not remove certificate map");
2788
2789
0
    return rc;
2790
0
}
2791
#endif /* NETSNMP_FEATURE_REMOVE_CERT_MAP_REMOVE */
2792
2793
#ifndef NETSNMP_FEATURE_REMOVE_CERT_MAP_FIND
2794
netsnmp_cert_map *
2795
netsnmp_cert_map_find(netsnmp_cert_map *map)
2796
0
{
2797
0
    if (NULL == map)
2798
0
        return NULL;
2799
2800
0
    return CONTAINER_FIND(_maps, map);
2801
0
}
2802
#endif /* NETSNMP_FEATURE_REMOVE_CERT_MAP_FIND */
2803
2804
static void
2805
_map_free(void *map, void *context)
2806
0
{
2807
0
    netsnmp_cert_map_free(map);
2808
0
}
2809
2810
static int
2811
_map_compare(const void *p, const void *q)
2812
0
{
2813
0
    const netsnmp_cert_map *lhs = p, *rhs = q;
2814
2815
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
2816
2817
0
    if (lhs->priority < rhs->priority)
2818
0
        return -1;
2819
0
    else if (lhs->priority > rhs->priority)
2820
0
        return 1;
2821
2822
0
    return strcmp(lhs->fingerprint, rhs->fingerprint);
2823
0
}
2824
2825
static int
2826
_map_fp_compare(const void *p, const void *q)
2827
0
{
2828
0
    const netsnmp_cert_map *lhs = p, *rhs = q;
2829
0
    int rc;
2830
2831
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
2832
2833
0
    if ((rc = strcmp(lhs->fingerprint, rhs->fingerprint)) != 0)
2834
0
        return rc;
2835
2836
0
    if (lhs->priority < rhs->priority)
2837
0
        return -1;
2838
0
    else if (lhs->priority > rhs->priority)
2839
0
        return 1;
2840
2841
0
    return 0;
2842
0
}
2843
2844
static int
2845
_map_fp_ncompare(const void *p, const void *q)
2846
0
{
2847
0
    const netsnmp_cert_map *lhs = p, *rhs = q;
2848
2849
0
    netsnmp_assert((lhs != NULL) && (rhs != NULL));
2850
2851
0
    return strncmp(lhs->fingerprint, rhs->fingerprint,
2852
0
                   strlen(rhs->fingerprint));
2853
0
}
2854
2855
netsnmp_container *
2856
netsnmp_cert_map_container_create(int with_fp)
2857
2.79k
{
2858
2.79k
    netsnmp_container *chain_map, *fp;
2859
2860
2.79k
    chain_map = netsnmp_container_find("cert_map:stack:binary_array");
2861
2.79k
    if (NULL == chain_map) {
2862
0
        snmp_log(LOG_ERR, "could not allocate container for cert_map\n");
2863
0
        return NULL;
2864
0
    }
2865
2866
2.79k
    chain_map->container_name = strdup("cert_map");
2867
2.79k
    chain_map->free_item = _map_free;
2868
2.79k
    chain_map->compare = _map_compare;
2869
2870
2.79k
    if (!with_fp)
2871
0
        return chain_map;
2872
2873
    /*
2874
     * add a secondary index to the table container
2875
     */
2876
2.79k
    fp = netsnmp_container_find("cert2sn_fp:binary_array");
2877
2.79k
    if (NULL == fp) {
2878
0
        snmp_log(LOG_ERR,
2879
0
                 "error creating sub-container for tlstmCertToTSNTable\n");
2880
0
        CONTAINER_FREE(chain_map);
2881
0
        return NULL;
2882
0
    }
2883
2.79k
    fp->container_name = strdup("cert2sn_fp");
2884
2.79k
    fp->compare = _map_fp_compare;
2885
2.79k
    fp->ncompare = _map_fp_ncompare;
2886
2.79k
    netsnmp_container_add_index(chain_map, fp);
2887
2888
2.79k
    return chain_map;
2889
2.79k
}
2890
2891
int
2892
netsnmp_cert_parse_hash_type(const char *str)
2893
0
{
2894
0
    int rc = se_find_value_in_slist("cert_hash_alg", str);
2895
0
    if (SE_DNE == rc)
2896
0
        return NS_HASH_NONE;
2897
0
    return rc;
2898
0
}
2899
2900
void
2901
netsnmp_cert_map_container_free(netsnmp_container *c)
2902
0
{
2903
0
    if (NULL == c)
2904
0
        return;
2905
2906
0
    CONTAINER_FREE_ALL(c, NULL);
2907
0
    CONTAINER_FREE(c);
2908
0
}
2909
2910
/** clear out config rows
2911
 * called during reconfig processing (e.g. SIGHUP)
2912
*/
2913
static void
2914
_purge_config_entries(void)
2915
5.59k
{
2916
    /**
2917
     ** dup container
2918
     ** iterate looking for NSCM_FROM_CONFIG flag
2919
     ** delete from original
2920
     ** delete dup
2921
     **/
2922
5.59k
    netsnmp_iterator   *itr;
2923
5.59k
    netsnmp_cert_map   *cert_map;
2924
5.59k
    netsnmp_container  *cert_maps = netsnmp_cert_map_container();
2925
5.59k
    netsnmp_container  *tmp_maps = NULL;
2926
2927
5.59k
    if ((NULL == cert_maps) || (CONTAINER_SIZE(cert_maps) == 0))
2928
5.59k
        return;
2929
2930
0
    DEBUGMSGT(("cert:map:reconfig", "removing locally configured rows\n"));
2931
    
2932
    /*
2933
     * duplicate cert_maps and then iterate over the copy. That way we can
2934
     * add/remove to cert_maps without disturbing the iterator.
2935
xx
2936
     */
2937
0
    tmp_maps = CONTAINER_DUP(cert_maps, NULL, 0);
2938
0
    if (NULL == tmp_maps) {
2939
0
        snmp_log(LOG_ERR, "could not duplicate maps for reconfig\n");
2940
0
        return;
2941
0
    }
2942
2943
0
    itr = CONTAINER_ITERATOR(tmp_maps);
2944
0
    if (NULL == itr) {
2945
0
        snmp_log(LOG_ERR, "could not get iterator for reconfig\n");
2946
0
        CONTAINER_FREE(tmp_maps);
2947
0
        return;
2948
0
    }
2949
0
    cert_map = ITERATOR_FIRST(itr);
2950
0
    for( ; cert_map; cert_map = ITERATOR_NEXT(itr)) {
2951
2952
0
        if (!(cert_map->flags & NSCM_FROM_CONFIG))
2953
0
            continue;
2954
2955
0
        if (CONTAINER_REMOVE(cert_maps, cert_map) == 0)
2956
0
            netsnmp_cert_map_free(cert_map);
2957
0
    }
2958
0
    ITERATOR_RELEASE(itr);
2959
0
    CONTAINER_FREE(tmp_maps);
2960
2961
0
    return;
2962
0
}
2963
2964
/*
2965
  certSecName PRIORITY [--shaNN|md5] FINGERPRINT <--sn SECNAME | --rfc822 | --dns | --ip | --cn | --any>
2966
2967
  certSecName  100  ff:..11 --sn Wes
2968
  certSecName  200  ee:..:22 --sn JohnDoe
2969
  certSecName  300  ee:..:22 --rfc822
2970
*/
2971
netsnmp_cert_map *
2972
netsnmp_certToTSN_parse_common(char **line)
2973
0
{
2974
0
    netsnmp_cert_map *map;
2975
0
    char             *tmp, buf[SNMP_MAXBUF_SMALL];
2976
0
    size_t            len;
2977
0
    netsnmp_cert     *tmpcert;
2978
2979
0
    if ((NULL == line) || (NULL == *line))
2980
0
        return NULL;
2981
2982
    /** need somewhere to save rows */
2983
0
    if (NULL == _maps) {
2984
0
        NETSNMP_LOGONCE((LOG_ERR, "no container for certificate mappings\n"));
2985
0
        return NULL;
2986
0
    }
2987
2988
0
    DEBUGMSGT(("cert:util:config", "parsing %s\n", *line));
2989
2990
    /* read the priority */
2991
0
    len = sizeof(buf);
2992
0
    tmp = buf;
2993
0
    *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
2994
0
    tmp[len] = 0;
2995
0
    if (!isdigit(0xFF & tmp[0])) {
2996
0
        netsnmp_config_error("could not parse priority");
2997
0
        return NULL;
2998
0
    }
2999
0
    map = netsnmp_cert_map_alloc(NULL, NULL);
3000
0
    if (NULL == map) {
3001
0
        netsnmp_config_error("could not allocate cert map struct");
3002
0
        return NULL;
3003
0
    }
3004
0
    map->flags |= NSCM_FROM_CONFIG;
3005
0
    map->priority = atoi(buf);
3006
3007
    /* read the flag or the fingerprint */
3008
0
    len = sizeof(buf);
3009
0
    tmp = buf;
3010
0
    *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
3011
0
    tmp[len] = 0;
3012
0
    if ((buf[0] == '-') && (buf[1] == '-')) {
3013
0
        map->hashType = netsnmp_cert_parse_hash_type(&buf[2]);
3014
0
        if (NS_HASH_NONE == map->hashType) {
3015
0
            netsnmp_config_error("invalid hash type");
3016
0
            goto end;
3017
0
        }
3018
3019
        /** set up for fingerprint */
3020
0
        len = sizeof(buf);
3021
0
        tmp = buf;
3022
0
        *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
3023
0
        tmp[len] = 0;
3024
0
    }
3025
0
    else
3026
0
        map->hashType = NS_HASH_SHA1;
3027
3028
    /* look up the fingerprint */
3029
0
    tmpcert = netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_MULTIPLE, buf);
3030
0
    if (NULL == tmpcert) {
3031
        /* assume it's a raw fingerprint we don't have */
3032
0
        netsnmp_fp_lowercase_and_strip_colon(buf);
3033
0
        map->fingerprint = strdup(buf);
3034
0
    } else {
3035
0
        map->fingerprint =
3036
0
            netsnmp_openssl_cert_get_fingerprint(tmpcert->ocert, NS_HASH_SHA1);
3037
0
    }
3038
    
3039
0
    if (NULL == *line) {
3040
0
        netsnmp_config_error("must specify map type");
3041
0
        goto end;
3042
0
    }
3043
3044
    /* read the mapping type */
3045
0
    len = sizeof(buf);
3046
0
    tmp = buf;
3047
0
    *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
3048
0
    tmp[len] = 0;
3049
0
    if ((buf[0] != '-') || (buf[1] != '-')) {
3050
0
        netsnmp_config_error("unexpected format: %s\n", *line);
3051
0
        goto end;
3052
0
    }
3053
0
    if (strcmp(&buf[2], "sn") == 0) {
3054
0
        if (NULL == *line) {
3055
0
            netsnmp_config_error("must specify secName for --sn");
3056
0
            goto end;
3057
0
        }
3058
0
        len = sizeof(buf);
3059
0
        tmp = buf;
3060
0
        *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
3061
0
        map->data = strdup(buf);
3062
0
        if (map->data)
3063
0
            map->mapType = TSNM_tlstmCertSpecified;
3064
0
    }
3065
0
    else if (strcmp(&buf[2], "cn") == 0)
3066
0
        map->mapType = TSNM_tlstmCertCommonName;
3067
0
    else if (strcmp(&buf[2], "ip") == 0)
3068
0
        map->mapType = TSNM_tlstmCertSANIpAddress;
3069
0
    else if (strcmp(&buf[2], "rfc822") == 0)
3070
0
        map->mapType = TSNM_tlstmCertSANRFC822Name;
3071
0
    else if (strcmp(&buf[2], "dns") == 0)
3072
0
        map->mapType = TSNM_tlstmCertSANDNSName;
3073
0
    else if (strcmp(&buf[2], "any") == 0)
3074
0
        map->mapType = TSNM_tlstmCertSANAny;
3075
0
    else
3076
0
        netsnmp_config_error("unknown argument %s\n", buf);
3077
    
3078
0
  end:
3079
0
    if (0 == map->mapType) {
3080
0
        netsnmp_cert_map_free(map);
3081
0
        map = NULL;
3082
0
    }
3083
3084
0
    return map;
3085
0
}
3086
3087
static void
3088
_parse_map(const char *token, char *line)
3089
0
{
3090
0
    netsnmp_cert_map *map = netsnmp_certToTSN_parse_common(&line);
3091
0
    if (NULL == map)
3092
0
        return;
3093
3094
0
    if (netsnmp_cert_map_add(map) != 0) {
3095
0
        netsnmp_cert_map_free(map);
3096
0
        netsnmp_config_error(MAP_CONFIG_TOKEN
3097
0
                             ": duplicate priority for certificate map");
3098
0
    }
3099
0
}
3100
3101
static int
3102
_fill_cert_map(netsnmp_cert_map *cert_map, netsnmp_cert_map *entry)
3103
0
{
3104
0
    DEBUGMSGT(("cert:map:secname", "map: pri %d type %d data %s\n",
3105
0
               entry->priority, entry->mapType, entry->data));
3106
0
    cert_map->priority = entry->priority;
3107
0
    cert_map->mapType = entry->mapType;
3108
0
    cert_map->hashType = entry->hashType;
3109
0
    if (entry->data) {
3110
0
        cert_map->data = strdup(entry->data);
3111
0
        if (NULL == cert_map->data ) {
3112
0
            snmp_log(LOG_ERR, "secname map data dup failed\n");
3113
0
            return -1;
3114
0
        }
3115
0
    }
3116
3117
0
    return 0;
3118
0
}
3119
3120
/*
3121
 * get secname map(s) for fingerprints
3122
 */
3123
int
3124
netsnmp_cert_get_secname_maps(netsnmp_container *cert_maps)
3125
0
{
3126
0
    netsnmp_iterator   *itr;
3127
0
    netsnmp_cert_map   *cert_map, *new_cert_map, *entry;
3128
0
    netsnmp_container  *new_maps = NULL;
3129
0
    netsnmp_void_array *results;
3130
0
    int                 j;
3131
3132
0
    if ((NULL == cert_maps) || (CONTAINER_SIZE(cert_maps) == 0))
3133
0
        return -1;
3134
3135
0
    DEBUGMSGT(("cert:map:secname", "looking for matches for %" NETSNMP_PRIz "d fingerprints\n",
3136
0
               CONTAINER_SIZE(cert_maps)));
3137
    
3138
    /*
3139
     * duplicate cert_maps and then iterate over the copy. That way we can
3140
     * add/remove to cert_maps without disturbing the iterator.
3141
     */
3142
0
    new_maps = CONTAINER_DUP(cert_maps, NULL, 0);
3143
0
    if (NULL == new_maps) {
3144
0
        snmp_log(LOG_ERR, "could not duplicate maps for secname mapping\n");
3145
0
        return -1;
3146
0
    }
3147
3148
0
    itr = CONTAINER_ITERATOR(new_maps);
3149
0
    if (NULL == itr) {
3150
0
        snmp_log(LOG_ERR, "could not get iterator for secname mappings\n");
3151
0
        CONTAINER_FREE(new_maps);
3152
0
        return -1;
3153
0
    }
3154
0
    cert_map = ITERATOR_FIRST(itr);
3155
0
    for( ; cert_map; cert_map = ITERATOR_NEXT(itr)) {
3156
3157
0
        results = _find_subset_fp( netsnmp_cert_map_container(),
3158
0
                                   cert_map->fingerprint );
3159
0
        if (NULL == results) {
3160
0
            DEBUGMSGT(("cert:map:secname", "no match for %s\n",
3161
0
                       cert_map->fingerprint));
3162
0
            if (CONTAINER_REMOVE(cert_maps, cert_map) != 0)
3163
0
                goto fail;
3164
0
            continue;
3165
0
        }
3166
0
        DEBUGMSGT(("cert:map:secname", "%" NETSNMP_PRIz "d matches for %s\n",
3167
0
                   results->size, cert_map->fingerprint));
3168
        /*
3169
         * first entry is a freebie
3170
         */
3171
0
        entry = (netsnmp_cert_map*)results->array[0];
3172
0
        if (_fill_cert_map(cert_map, entry) != 0)
3173
0
            goto fail;
3174
3175
        /*
3176
         * additional entries must be allocated/inserted
3177
         */
3178
0
        if (results->size > 1) {
3179
0
            for(j=1; j < results->size; ++j) {
3180
0
                entry = (netsnmp_cert_map*)results->array[j];
3181
0
                new_cert_map = netsnmp_cert_map_alloc(entry->fingerprint,
3182
0
                                                      entry->ocert);
3183
0
                if (NULL == new_cert_map) {
3184
0
                    snmp_log(LOG_ERR,
3185
0
                             "could not allocate new cert map entry\n");
3186
0
                    goto fail;
3187
0
                }
3188
0
                if (_fill_cert_map(new_cert_map, entry) != 0) {
3189
0
                    netsnmp_cert_map_free(new_cert_map);
3190
0
                    goto fail;
3191
0
                }
3192
0
                new_cert_map->ocert = cert_map->ocert;
3193
0
                if (CONTAINER_INSERT(cert_maps,new_cert_map) != 0) {
3194
0
                    netsnmp_cert_map_free(new_cert_map);
3195
0
                    goto fail;
3196
0
                }
3197
0
            } /* for results */
3198
0
        } /* results size > 1 */
3199
3200
0
        free(results->array);
3201
0
        SNMP_FREE(results);
3202
0
    }
3203
0
    ITERATOR_RELEASE(itr);
3204
0
    CONTAINER_FREE(new_maps);
3205
3206
0
    DEBUGMSGT(("cert:map:secname",
3207
0
               "found %" NETSNMP_PRIz "d matches for fingerprints\n",
3208
0
               CONTAINER_SIZE(cert_maps)));
3209
0
    return 0;
3210
3211
0
  fail:
3212
0
    if (results) {
3213
0
        free(results->array);
3214
0
        free(results);
3215
0
    }
3216
0
    ITERATOR_RELEASE(itr);
3217
0
    CONTAINER_FREE(new_maps);
3218
0
    return -1;
3219
0
}
3220
3221
/* ***************************************************************************
3222
 * ***************************************************************************
3223
 *
3224
 *
3225
 * snmpTlstmParmsTable data
3226
 *
3227
 *
3228
 * ***************************************************************************
3229
 * ***************************************************************************/
3230
5.59k
#define PARAMS_CONFIG_TOKEN "snmpTlstmParams"
3231
static void _parse_params(const char *token, char *line);
3232
3233
static void
3234
_init_tlstmParams(void)
3235
2.79k
{
3236
2.79k
    const char *params_help = 
3237
2.79k
        PARAMS_CONFIG_TOKEN " targetParamsName hashType:fingerPrint";
3238
    
3239
    /*
3240
     * container for snmpTlstmParamsTable data
3241
     */
3242
2.79k
    _tlstmParams = netsnmp_container_find("tlstmParams:string");
3243
2.79k
    if (NULL == _tlstmParams)
3244
0
        snmp_log(LOG_ERR,
3245
0
                 "error creating sub-container for tlstmParamsTable\n");
3246
2.79k
    else
3247
2.79k
        _tlstmParams->container_name = strdup("tlstmParams");
3248
3249
2.79k
    register_config_handler(NULL, PARAMS_CONFIG_TOKEN, _parse_params, NULL,
3250
2.79k
                                params_help);
3251
2.79k
}
3252
3253
#ifndef NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_CONTAINER
3254
netsnmp_container *
3255
netsnmp_tlstmParams_container(void)
3256
0
{
3257
0
    return _tlstmParams;
3258
0
}
3259
#endif /* NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_CONTAINER */
3260
3261
snmpTlstmParams *
3262
netsnmp_tlstmParams_create(const char *name, int hashType, const char *fp,
3263
                           int fp_len)
3264
0
{
3265
0
    snmpTlstmParams *stp = SNMP_MALLOC_TYPEDEF(snmpTlstmParams);
3266
0
    if (NULL == stp)
3267
0
        return NULL;
3268
3269
0
    if (name)
3270
0
        stp->name = strdup(name);
3271
0
    stp->hashType = hashType;
3272
0
    if (fp)
3273
0
        stp->fingerprint = strdup(fp);
3274
0
    DEBUGMSGT(("9:tlstmParams:create", "%p: %s\n", stp,
3275
0
               stp->name ? stp->name : "null"));
3276
3277
0
    return stp;
3278
0
}
3279
3280
void
3281
netsnmp_tlstmParams_free(snmpTlstmParams *stp)
3282
0
{
3283
0
    if (NULL == stp)
3284
0
        return;
3285
3286
0
    DEBUGMSGT(("9:tlstmParams:release", "%p %s\n", stp,
3287
0
               stp->name ? stp->name : "null"));
3288
0
    SNMP_FREE(stp->name);
3289
0
    SNMP_FREE(stp->fingerprint);
3290
0
    free(stp); /* SNMP_FREE pointless on parameter */
3291
0
}
3292
3293
snmpTlstmParams *
3294
netsnmp_tlstmParams_restore_common(char **line)
3295
0
{
3296
0
    snmpTlstmParams  *stp;
3297
0
    char             *tmp, buf[SNMP_MAXBUF_SMALL];
3298
0
    size_t            len;
3299
3300
0
    if ((NULL == line) || (NULL == *line))
3301
0
        return NULL;
3302
3303
    /** need somewhere to save rows */
3304
0
    netsnmp_assert(_tlstmParams);
3305
3306
0
    stp = netsnmp_tlstmParams_create(NULL, 0, NULL, 0);
3307
0
    if (NULL == stp)
3308
0
        return NULL;
3309
3310
    /** name */
3311
0
    len = sizeof(buf);
3312
0
    tmp = buf;
3313
0
    *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
3314
0
    tmp[len] = 0;
3315
    /** xxx-rks: validate snmpadminstring? */
3316
0
    if (len)
3317
0
        stp->name = strdup(buf);
3318
3319
    /** fingerprint hash type*/
3320
0
    len = sizeof(buf);
3321
0
    tmp = buf;
3322
0
    *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
3323
0
    tmp[len] = 0;
3324
0
    if ((buf[0] == '-') && (buf[1] == '-')) {
3325
0
        stp->hashType = netsnmp_cert_parse_hash_type(&buf[2]);
3326
3327
        /** set up for fingerprint */
3328
0
        len = sizeof(buf);
3329
0
        tmp = buf;
3330
0
        *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
3331
0
        tmp[len] = 0;
3332
0
    }
3333
0
    else
3334
0
        stp->hashType =NS_HASH_SHA1;
3335
    
3336
0
    netsnmp_fp_lowercase_and_strip_colon(buf);
3337
0
    stp->fingerprint = strdup(buf);
3338
0
    stp->fingerprint_len = strlen(buf);
3339
3340
0
    DEBUGMSGTL(("tlstmParams:restore:common", "name '%s'\n", stp->name));
3341
3342
0
    return stp;
3343
0
}
3344
3345
int
3346
netsnmp_tlstmParams_add(snmpTlstmParams *stp)
3347
0
{
3348
0
    if (NULL == stp)
3349
0
        return -1;
3350
3351
0
    DEBUGMSGTL(("tlstmParams:add", "adding entry %p %s\n", stp, stp->name));
3352
3353
0
    if (CONTAINER_INSERT(_tlstmParams, stp) != 0) {
3354
0
        snmp_log(LOG_ERR, "error inserting tlstmParams %s", stp->name);
3355
0
        netsnmp_tlstmParams_free(stp);
3356
0
        return -1;
3357
0
    }
3358
3359
0
    return 0;
3360
0
}
3361
3362
#ifndef NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_REMOVE
3363
int
3364
netsnmp_tlstmParams_remove(snmpTlstmParams *stp)
3365
0
{
3366
0
    if (NULL == stp)
3367
0
        return -1;
3368
3369
0
    DEBUGMSGTL(("tlstmParams:remove", "removing entry %p %s\n", stp,
3370
0
                stp->name));
3371
3372
0
    if (CONTAINER_REMOVE(_tlstmParams, stp) != 0) {
3373
0
        snmp_log(LOG_ERR, "error removing tlstmParams %s", stp->name);
3374
0
        return -1;
3375
0
    }
3376
3377
0
    return 0;
3378
0
}
3379
#endif /* NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_REMOVE */
3380
3381
#ifndef NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_FIND
3382
snmpTlstmParams *
3383
netsnmp_tlstmParams_find(snmpTlstmParams *stp)
3384
0
{
3385
0
    snmpTlstmParams *found;
3386
3387
0
    if (NULL == stp)
3388
0
        return NULL;
3389
3390
0
    found = CONTAINER_FIND(_tlstmParams, stp);
3391
0
    return found;
3392
0
}
3393
#endif /* NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_FIND */
3394
3395
static void
3396
_parse_params(const char *token, char *line)
3397
0
{
3398
0
    snmpTlstmParams *stp = netsnmp_tlstmParams_restore_common(&line);
3399
3400
0
    if (!stp)
3401
0
        return;
3402
3403
0
    stp->flags = TLSTM_PARAMS_FROM_CONFIG | TLSTM_PARAMS_NONVOLATILE;
3404
3405
0
    netsnmp_tlstmParams_add(stp);
3406
0
}
3407
3408
static char *
3409
_find_tlstmParams_fingerprint(const char *name)
3410
0
{
3411
0
    snmpTlstmParams lookup_key, *result;
3412
3413
0
    if (NULL == name)
3414
0
        return NULL;
3415
3416
0
    lookup_key.name = NETSNMP_REMOVE_CONST(char*, name);
3417
3418
0
    result = CONTAINER_FIND(_tlstmParams, &lookup_key);
3419
0
    if ((NULL == result) || (NULL == result->fingerprint))
3420
0
        return NULL;
3421
3422
0
    return result->fingerprint;
3423
0
}
3424
/*
3425
 * END snmpTlstmParmsTable data
3426
 * ***************************************************************************/
3427
3428
/* ***************************************************************************
3429
 * ***************************************************************************
3430
 *
3431
 *
3432
 * snmpTlstmAddrTable data
3433
 *
3434
 *
3435
 * ***************************************************************************
3436
 * ***************************************************************************/
3437
5.59k
#define ADDR_CONFIG_TOKEN "snmpTlstmAddr"
3438
static void _parse_addr(const char *token, char *line);
3439
3440
static void
3441
_init_tlstmAddr(void)
3442
2.79k
{
3443
2.79k
    const char *addr_help = 
3444
2.79k
        ADDR_CONFIG_TOKEN " targetAddrName hashType:fingerprint serverIdentity";
3445
    
3446
    /*
3447
     * container for snmpTlstmAddrTable data
3448
     */
3449
2.79k
    _tlstmAddr = netsnmp_container_find("tlstmAddr:string");
3450
2.79k
    if (NULL == _tlstmAddr)
3451
0
        snmp_log(LOG_ERR,
3452
0
                 "error creating sub-container for tlstmAddrTable\n");
3453
2.79k
    else
3454
2.79k
        _tlstmAddr->container_name = strdup("tlstmAddr");
3455
3456
2.79k
    register_config_handler(NULL, ADDR_CONFIG_TOKEN, _parse_addr, NULL,
3457
2.79k
                            addr_help);
3458
2.79k
}
3459
3460
#ifndef NETSNMP_FEATURE_REMOVE_TLSTMADDR_CONTAINER
3461
netsnmp_container *
3462
netsnmp_tlstmAddr_container(void)
3463
0
{
3464
0
    return _tlstmAddr;
3465
0
}
3466
#endif /* NETSNMP_FEATURE_REMOVE_TLSTMADDR_CONTAINER */
3467
3468
/*
3469
 * create a new row in the table 
3470
 */
3471
snmpTlstmAddr *
3472
netsnmp_tlstmAddr_create(char *targetAddrName)
3473
0
{
3474
0
    snmpTlstmAddr *entry;
3475
3476
0
    if (NULL == targetAddrName)
3477
0
        return NULL;
3478
3479
0
    entry = SNMP_MALLOC_TYPEDEF(snmpTlstmAddr);
3480
0
    if (!entry)
3481
0
        return NULL;
3482
3483
0
    DEBUGMSGT(("tlstmAddr:entry:create", "entry %p %s\n", entry,
3484
0
               targetAddrName ? targetAddrName : "NULL"));
3485
3486
0
    entry->name = strdup(targetAddrName);
3487
3488
0
    return entry;
3489
0
}
3490
3491
void
3492
netsnmp_tlstmAddr_free(snmpTlstmAddr *entry)
3493
0
{
3494
0
    if (!entry)
3495
0
        return;
3496
3497
0
    SNMP_FREE(entry->name);
3498
0
    SNMP_FREE(entry->fingerprint);
3499
0
    SNMP_FREE(entry->identity);
3500
0
    free(entry);
3501
0
}
3502
3503
int
3504
netsnmp_tlstmAddr_restore_common(char **line, char *name, size_t *name_len,
3505
                                 char *id, size_t *id_len, char *fp,
3506
                                 size_t *fp_len, u_char *ht)
3507
0
{
3508
0
    size_t fp_len_save = *fp_len - 1;
3509
3510
    /*
3511
     * Calling this function with name == NULL, fp == NULL or id == NULL would
3512
     * trigger a memory leak.
3513
     */
3514
0
    if (!name || !fp || !id || *name_len == 0 || *id_len == 0 || *fp_len == 0)
3515
0
        return -1;
3516
3517
0
    (*name_len)--;
3518
0
    (*fp_len)--;
3519
0
    (*id_len)--;
3520
3521
0
    *line = read_config_read_octet_string(*line, (u_char **)&name, name_len);
3522
0
    if (NULL == *line) {
3523
0
        config_perror("incomplete line");
3524
0
        return -1;
3525
0
    }
3526
0
    name[*name_len] = 0;
3527
3528
0
    *line = read_config_read_octet_string(*line, (u_char **)&fp, fp_len);
3529
0
    if (NULL == *line) {
3530
0
        config_perror("incomplete line");
3531
0
        return -1;
3532
0
    }
3533
0
    fp[*fp_len] = 0;
3534
0
    if ((fp[0] == '-') && (fp[1] == '-')) {
3535
0
        *ht = netsnmp_cert_parse_hash_type(&fp[2]);
3536
        
3537
        /** set up for fingerprint */
3538
0
        *fp_len = fp_len_save;
3539
0
        *line = read_config_read_octet_string(*line, (u_char **)&fp, fp_len);
3540
0
        fp[*fp_len] = 0;
3541
0
    }
3542
0
    else
3543
0
        *ht = NS_HASH_SHA1;
3544
0
    netsnmp_fp_lowercase_and_strip_colon(fp);
3545
0
    *fp_len = strlen(fp);
3546
    
3547
0
    *line = read_config_read_octet_string(*line, (u_char **)&id, id_len);
3548
0
    id[*id_len] = 0;
3549
    
3550
0
    if (*ht <= NS_HASH_NONE || *ht > NS_HASH_MAX) {
3551
0
        config_perror("invalid algorithm for fingerprint");
3552
0
        return -1;
3553
0
    }
3554
3555
0
    if ((0 == *fp_len) && ((0 == *id_len || (*id_len == 1 && id[0] == '*')))) {
3556
        /*
3557
         * empty fingerprint not allowed with '*' identity
3558
         */
3559
0
        config_perror("must specify fingerprint for '*' identity");
3560
0
        return -1;
3561
0
    }
3562
3563
0
    return 0;
3564
0
}
3565
3566
int
3567
netsnmp_tlstmAddr_add(snmpTlstmAddr *entry)
3568
0
{
3569
0
    if (!entry)
3570
0
        return -1;
3571
3572
0
    DEBUGMSGTL(("tlstmAddr:add", "adding entry %p %s %s\n",
3573
0
                entry, entry->name, entry->fingerprint));
3574
0
    if (CONTAINER_INSERT(_tlstmAddr, entry) != 0) {
3575
0
        snmp_log(LOG_ERR, "could not insert addr %s", entry->name);
3576
0
        netsnmp_tlstmAddr_free(entry);
3577
0
        return -1;
3578
0
    }
3579
3580
0
    return 0;
3581
0
}
3582
3583
#ifndef NETSNMP_FEATURE_REMOVE_TLSTMADDR_REMOVE
3584
int
3585
netsnmp_tlstmAddr_remove(snmpTlstmAddr *entry)
3586
0
{
3587
0
    if (!entry)
3588
0
        return -1;
3589
3590
0
    if (CONTAINER_REMOVE(_tlstmAddr, entry) != 0) {
3591
0
        snmp_log(LOG_ERR, "could not remove addr %s", entry->name);
3592
0
        return -1;
3593
0
    }
3594
3595
0
    return 0;
3596
0
}
3597
#endif /* NETSNMP_FEATURE_REMOVE_TLSTMADDR_REMOVE */
3598
3599
static void
3600
_parse_addr(const char *token, char *line)
3601
0
{
3602
0
    snmpTlstmAddr *entry;
3603
0
    char           name[SNMPADMINLENGTH  + 1], id[SNMPADMINLENGTH  + 1],
3604
0
                   fingerprint[SNMPTLSFINGERPRINT_MAX_LEN + 1];
3605
0
    size_t         name_len = sizeof(name), id_len = sizeof(id),
3606
0
                   fp_len = sizeof(fingerprint);
3607
0
    u_char         hashType;
3608
0
    int            rc;
3609
3610
0
    rc = netsnmp_tlstmAddr_restore_common(&line, name, &name_len, id, &id_len,
3611
0
                                          fingerprint, &fp_len, &hashType);
3612
0
    if (rc < 0)
3613
0
        return;
3614
3615
0
    if (NULL != line)
3616
0
        config_pwarn("ignore extra tokens on line");
3617
3618
0
    entry = netsnmp_tlstmAddr_create(name);
3619
0
    if (NULL == entry)
3620
0
        return;
3621
3622
0
    entry->flags |= TLSTM_ADDR_FROM_CONFIG;
3623
0
    entry->hashType = hashType;
3624
0
    if (fp_len)
3625
0
        entry->fingerprint = strdup(fingerprint);
3626
0
    if (id_len)
3627
0
        entry->identity = strdup(id);
3628
3629
0
    netsnmp_tlstmAddr_add(entry);
3630
0
}
3631
3632
static char *
3633
_find_tlstmAddr_fingerprint(const char *name)
3634
0
{
3635
0
    snmpTlstmAddr    lookup_key, *result;
3636
3637
0
    if (NULL == name)
3638
0
        return NULL;
3639
3640
0
    lookup_key.name = NETSNMP_REMOVE_CONST(char*, name);
3641
3642
0
    result = CONTAINER_FIND(_tlstmAddr, &lookup_key);
3643
0
    if (NULL == result)
3644
0
        return NULL;
3645
3646
0
    return result->fingerprint;
3647
0
}
3648
3649
#ifndef NETSNMP_FEATURE_REMOVE_TLSTMADDR_GET_SERVERID
3650
char *
3651
netsnmp_tlstmAddr_get_serverId(const char *name)
3652
0
{
3653
0
    snmpTlstmAddr    lookup_key, *result;
3654
3655
0
    if (NULL == name)
3656
0
        return NULL;
3657
3658
0
    lookup_key.name = NETSNMP_REMOVE_CONST(char*, name);
3659
3660
0
    result = CONTAINER_FIND(_tlstmAddr, &lookup_key);
3661
0
    if (NULL == result)
3662
0
        return NULL;
3663
3664
0
    return result->identity;
3665
0
}
3666
#endif /* NETSNMP_FEATURE_REMOVE_TLSTMADDR_GET_SERVERID */
3667
/*
3668
 * END snmpTlstmAddrTable data
3669
 * ***************************************************************************/
3670
3671
#else
3672
netsnmp_feature_unused(cert_util);
3673
#endif /* NETSNMP_FEATURE_REMOVE_CERT_UTIL */
3674
netsnmp_feature_unused(cert_util);
3675
#endif /* defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && NETSNMP_TRANSPORT_TLSBASE_DOMAIN */