Coverage Report

Created: 2025-10-10 07:09

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