Coverage Report

Created: 2026-07-16 06:27

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