Coverage Report

Created: 2026-10-19 06:44

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