Coverage Report

Created: 2023-06-07 06:42

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