net-snmp 5.7
cert_util.c
00001 #include <net-snmp/net-snmp-config.h>
00002 #include <net-snmp/net-snmp-features.h>
00003 
00004 #if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL)
00005 netsnmp_feature_child_of(cert_util_all, libnetsnmp)
00006 netsnmp_feature_child_of(cert_util, cert_util_all)
00007 #ifdef NETSNMP_FEATURE_REQUIRE_CERT_UTIL
00008 netsnmp_feature_require(container_directory)
00009 netsnmp_feature_require(container_fifo)
00010 netsnmp_feature_require(container_dup)
00011 netsnmp_feature_require(container_free_all)
00012 netsnmp_feature_require(subcontainer_find)
00013 
00014 netsnmp_feature_child_of(cert_map_remove, netsnmp_unused)
00015 netsnmp_feature_child_of(cert_map_find, netsnmp_unused)
00016 netsnmp_feature_child_of(tlstmparams_external, cert_util_all)
00017 netsnmp_feature_child_of(tlstmparams_container, tlstmparams_external)
00018 netsnmp_feature_child_of(tlstmparams_remove, tlstmparams_external)
00019 netsnmp_feature_child_of(tlstmparams_find, tlstmparams_external)
00020 netsnmp_feature_child_of(tlstmAddr_remove, netsnmp_unused)
00021 netsnmp_feature_child_of(tlstmaddr_external, cert_util_all)
00022 netsnmp_feature_child_of(tlstmaddr_container, tlstmaddr_external)
00023 netsnmp_feature_child_of(tlstmAddr_get_serverId, tlstmaddr_external)
00024 
00025 netsnmp_feature_child_of(cert_fingerprints, cert_util_all)
00026 netsnmp_feature_child_of(tls_fingerprint_build, cert_util_all)
00027 
00028 #endif /* NETSNMP_FEATURE_REQUIRE_CERT_UTIL */
00029 
00030 #ifndef NETSNMP_FEATURE_REMOVE_CERT_UTIL
00031 
00032 #include <ctype.h>
00033 
00034 #if HAVE_STDLIB_H
00035 #include <stdlib.h>
00036 #endif
00037 
00038 #if HAVE_STRING_H
00039 #include <string.h>
00040 #else
00041 #include <strings.h>
00042 #endif
00043 
00044 #if HAVE_SYS_STAT_H
00045 #   include <sys/stat.h>
00046 #endif
00047 #if HAVE_DIRENT_H
00048 # include <dirent.h>
00049 # define NAMLEN(dirent) strlen((dirent)->d_name)
00050 #else
00051 # define dirent direct
00052 # define NAMLEN(dirent) (dirent)->d_namlen
00053 # if HAVE_SYS_NDIR_H
00054 #  include <sys/ndir.h>
00055 # endif
00056 # if HAVE_SYS_DIR_H
00057 #  include <sys/dir.h>
00058 # endif
00059 # if HAVE_NDIR_H
00060 #  include <ndir.h>
00061 # endif
00062 #endif
00063 
00064 #if HAVE_DMALLOC_H
00065 #include <dmalloc.h>
00066 #endif
00067 
00068 #include <net-snmp/types.h>
00069 #include <net-snmp/output_api.h>
00070 #include <net-snmp/config_api.h>
00071 
00072 #include <net-snmp/library/snmp_assert.h>
00073 #include <net-snmp/library/snmp_transport.h>
00074 #include <net-snmp/library/system.h>
00075 #include <net-snmp/library/tools.h>
00076 #include <net-snmp/library/container.h>
00077 #include <net-snmp/library/data_list.h>
00078 #include <net-snmp/library/file_utils.h>
00079 #include <net-snmp/library/dir_utils.h>
00080 #include <net-snmp/library/read_config.h>
00081 
00082 #include <openssl/ssl.h>
00083 #include <openssl/err.h>
00084 #include <openssl/x509v3.h>
00085 #include <net-snmp/library/cert_util.h>
00086 #include <net-snmp/library/snmp_openssl.h>
00087 
00088 #ifndef NAME_MAX
00089 #define NAME_MAX 255
00090 #endif
00091 
00092 /*
00093  * bump this value whenever cert index format changes, so indexes
00094  * will be regenerated with new format.
00095  */
00096 #define CERT_INDEX_FORMAT  1
00097 
00098 static netsnmp_container *_certs = NULL;
00099 static netsnmp_container *_keys = NULL;
00100 static netsnmp_container *_maps = NULL;
00101 static netsnmp_container *_tlstmParams = NULL;
00102 static netsnmp_container *_tlstmAddr = NULL;
00103 static struct snmp_enum_list *_certindexes = NULL;
00104 
00105 static netsnmp_container *_trusted_certs = NULL;
00106 
00107 static void _setup_containers(void);
00108 
00109 static void _cert_indexes_load(void);
00110 static void _cert_free(netsnmp_cert *cert, void *context);
00111 static void _key_free(netsnmp_key *key, void *context);
00112 static int  _cert_compare(netsnmp_cert *lhs, netsnmp_cert *rhs);
00113 static int  _cert_sn_compare(netsnmp_cert *lhs, netsnmp_cert *rhs);
00114 static int  _cert_sn_ncompare(netsnmp_cert *lhs, netsnmp_cert *rhs);
00115 static int  _cert_cn_compare(netsnmp_cert *lhs, netsnmp_cert *rhs);
00116 static int  _cert_fn_compare(netsnmp_cert_common *lhs,
00117                              netsnmp_cert_common *rhs);
00118 static int  _cert_fn_ncompare(netsnmp_cert_common *lhs,
00119                               netsnmp_cert_common *rhs);
00120 static void _find_partner(netsnmp_cert *cert, netsnmp_key *key);
00121 static netsnmp_cert *_find_issuer(netsnmp_cert *cert);
00122 static netsnmp_void_array *_cert_find_subset_fn(const char *filename,
00123                                                 const char *directory);
00124 static netsnmp_void_array *_cert_find_subset_sn(const char *subject);
00125 static netsnmp_void_array *_key_find_subset(const char *filename);
00126 static netsnmp_cert *_cert_find_fp(const char *fingerprint);
00127 static char *_find_tlstmParams_fingerprint(const char *param);
00128 static char *_find_tlstmAddr_fingerprint(const char *name);
00129 static const char *_mode_str(u_char mode);
00130 static const char *_where_str(u_int what);
00131 void netsnmp_cert_dump_all(void);
00132 
00133 int netsnmp_cert_load_x509(netsnmp_cert *cert);
00134 
00135 void netsnmp_cert_free(netsnmp_cert *cert);
00136 void netsnmp_key_free(netsnmp_key *key);
00137 
00138 static int _certindex_add( const char *dirname, int i );
00139 
00140 static int _time_filter(netsnmp_file *f, struct stat *idx);
00141 
00142 static void _init_tlstmCertToTSN(void);
00143 #define TRUSTCERT_CONFIG_TOKEN "trustCert"
00144 static void _parse_trustcert(const char *token, char *line);
00145 
00146 static void _init_tlstmParams(void);
00147 static void _init_tlstmAddr(void);
00148 
00150 static const char _modes[][256] =
00151         {
00152             "none",
00153             "identity",
00154             "remote_peer",
00155             "identity+remote_peer",
00156             "reserved1",
00157             "reserved1+identity",
00158             "reserved1+remote_peer",
00159             "reserved1+identity+remote_peer",
00160             "CA",
00161             "CA+identity",
00162             "CA+remote_peer",
00163             "CA+identity+remote_peer",
00164             "CA+reserved1",
00165             "CA+reserved1+identity",
00166             "CA+reserved1+remote_peer",
00167             "CA+reserved1+identity+remote_peer",
00168         };
00169 
00170 /* #####################################################################
00171  *
00172  * init and shutdown functions
00173  *
00174  */
00175 
00176 void
00177 _netsnmp_release_trustcerts(void)
00178 {
00179     if (NULL != _trusted_certs) {
00180         CONTAINER_FREE_ALL(_trusted_certs, NULL);
00181         CONTAINER_FREE(_trusted_certs);
00182         _trusted_certs = NULL;
00183     }
00184 }
00185 
00186 void
00187 _setup_trusted_certs(void)
00188 {
00189     _trusted_certs = netsnmp_container_find("trusted_certs:fifo");
00190     if (NULL == _trusted_certs) {
00191         snmp_log(LOG_ERR, "could not create container for trusted certs\n");
00192         netsnmp_certs_shutdown();
00193         return;
00194     }
00195     _trusted_certs->container_name = strdup("trusted certificates");
00196     _trusted_certs->free_item = (netsnmp_container_obj_func*) free;
00197     _trusted_certs->compare = (netsnmp_container_compare*) strcmp;
00198 }
00199 
00200 /*
00201  * secname mapping for servers.
00202  */
00203 void
00204 netsnmp_certs_agent_init(void)
00205 {
00206     _init_tlstmCertToTSN();
00207     _init_tlstmParams();
00208     _init_tlstmAddr();
00209 }
00210 
00211 void
00212 netsnmp_certs_init(void)
00213 {
00214     const char *trustCert_help = TRUSTCERT_CONFIG_TOKEN
00215         " FINGERPRINT|FILENAME";
00216 
00217     register_config_handler("snmp", TRUSTCERT_CONFIG_TOKEN,
00218                             _parse_trustcert, _netsnmp_release_trustcerts,
00219                             trustCert_help);
00220     _setup_containers();
00221 
00223     se_add_pair_to_slist("cert_types", strdup("pem"), NS_CERT_TYPE_PEM);
00224     se_add_pair_to_slist("cert_types", strdup("crt"), NS_CERT_TYPE_DER);
00225     se_add_pair_to_slist("cert_types", strdup("cer"), NS_CERT_TYPE_DER);
00226     se_add_pair_to_slist("cert_types", strdup("cert"), NS_CERT_TYPE_DER);
00227     se_add_pair_to_slist("cert_types", strdup("der"), NS_CERT_TYPE_DER);
00228     se_add_pair_to_slist("cert_types", strdup("key"), NS_CERT_TYPE_KEY);
00229     se_add_pair_to_slist("cert_types", strdup("private"), NS_CERT_TYPE_KEY);
00230 
00232     se_add_pair_to_slist("cert_hash_alg", strdup("sha1"), NS_HASH_SHA1);
00233     se_add_pair_to_slist("cert_hash_alg", strdup("md5"), NS_HASH_MD5);
00234     se_add_pair_to_slist("cert_hash_alg", strdup("sha224"), NS_HASH_SHA224);
00235     se_add_pair_to_slist("cert_hash_alg", strdup("sha256"), NS_HASH_SHA256);
00236     se_add_pair_to_slist("cert_hash_alg", strdup("sha384"), NS_HASH_SHA384);
00237     se_add_pair_to_slist("cert_hash_alg", strdup("sha512"), NS_HASH_SHA512);
00238 
00240     se_add_pair_to_slist("cert_map_type", strdup("cn"),
00241                          TSNM_tlstmCertCommonName);
00242     se_add_pair_to_slist("cert_map_type", strdup("ip"),
00243                          TSNM_tlstmCertSANIpAddress);
00244     se_add_pair_to_slist("cert_map_type", strdup("rfc822"),
00245                          TSNM_tlstmCertSANRFC822Name);
00246     se_add_pair_to_slist("cert_map_type", strdup("dns"),
00247                          TSNM_tlstmCertSANDNSName);
00248     se_add_pair_to_slist("cert_map_type", strdup("any"), TSNM_tlstmCertSANAny);
00249     se_add_pair_to_slist("cert_map_type", strdup("sn"),
00250                          TSNM_tlstmCertSpecified);
00251 
00252 }
00253 
00254 void
00255 netsnmp_certs_shutdown(void)
00256 {
00257     DEBUGMSGT(("cert:util:shutdown","shutdown\n"));
00258     if (_maps) {
00259         CONTAINER_FREE_ALL(_maps, NULL);
00260         CONTAINER_FREE(_maps);
00261         _maps = NULL;
00262     }
00263     if (NULL != _certs) {
00264         CONTAINER_FREE_ALL(_certs, NULL);
00265         CONTAINER_FREE(_certs);
00266         _certs = NULL;
00267     }
00268     if (NULL != _keys) {
00269         CONTAINER_FREE_ALL(_keys, NULL);
00270         CONTAINER_FREE(_keys);
00271         _keys = NULL;
00272     }
00273     _netsnmp_release_trustcerts();
00274 }
00275 
00276 void
00277 netsnmp_certs_load(void)
00278 {
00279     netsnmp_iterator  *itr;
00280     netsnmp_key        *key;
00281     netsnmp_cert       *cert;
00282 
00283     DEBUGMSGT(("cert:util:init","init\n"));
00284 
00285     if (NULL == _certs) {
00286         snmp_log(LOG_ERR, "cant load certs without container\n");
00287         return;
00288     }
00289 
00290     if (CONTAINER_SIZE(_certs) != 0) {
00291         DEBUGMSGT(("cert:util:init", "ignoring duplicate init\n"));
00292         return;
00293     }
00294 
00295     netsnmp_init_openssl();
00296 
00298     _cert_indexes_load();
00299 
00301     itr = CONTAINER_ITERATOR(_keys);
00302     if (NULL == itr) {
00303         snmp_log(LOG_ERR, "could not get iterator for keys\n");
00304         netsnmp_certs_shutdown();
00305         return;
00306     }
00307     key = ITERATOR_FIRST(itr);
00308     for( ; key; key = ITERATOR_NEXT(itr))
00309         _find_partner(NULL, key);
00310     ITERATOR_RELEASE(itr);
00311 
00312     DEBUGIF("cert:dump") {
00313         itr = CONTAINER_ITERATOR(_certs);
00314         if (NULL == itr) {
00315             snmp_log(LOG_ERR, "could not get iterator for certs\n");
00316             netsnmp_certs_shutdown();
00317             return;
00318         }
00319         cert = ITERATOR_FIRST(itr);
00320         for( ; cert; cert = ITERATOR_NEXT(itr)) {
00321             netsnmp_cert_load_x509(cert);
00322         }
00323         ITERATOR_RELEASE(itr);
00324         DEBUGMSGT(("cert:dump",
00325                    "-------------------- Certificates -----------------\n"));
00326         netsnmp_cert_dump_all();
00327         DEBUGMSGT(("cert:dump",
00328                    "------------------------ End ----------------------\n"));
00329     }
00330 }
00331 
00332 /* #####################################################################
00333  *
00334  * cert container functions
00335  */
00336 
00337 static netsnmp_container *
00338 _get_cert_container(const char *use)
00339 {
00340     netsnmp_container *c;
00341 
00342     c = netsnmp_container_find("certs:binary_array");
00343     if (NULL == c) {
00344         snmp_log(LOG_ERR, "could not create container for %s\n", use);
00345         return NULL;
00346     }
00347     c->container_name = strdup(use);
00348     c->free_item = (netsnmp_container_obj_func*)_cert_free;
00349     c->compare = (netsnmp_container_compare*)_cert_compare;
00350 
00351     return c;
00352 }
00353 
00354 static void
00355 _setup_containers(void)
00356 {
00357     netsnmp_container *additional_keys;
00358 
00359     _certs = _get_cert_container("netsnmp certificates");
00360     if (NULL == _certs)
00361         return;
00362 
00364     additional_keys = netsnmp_container_find("certs_cn:binary_array");
00365     if (NULL == additional_keys) {
00366         snmp_log(LOG_ERR, "could not create CN container for certificates\n");
00367         netsnmp_certs_shutdown();
00368         return;
00369     }
00370     additional_keys->container_name = strdup("certs_cn");
00371     additional_keys->free_item = NULL;
00372     additional_keys->compare = (netsnmp_container_compare*)_cert_cn_compare;
00373     netsnmp_container_add_index(_certs, additional_keys);
00374 
00376     additional_keys = netsnmp_container_find("certs_sn:binary_array");
00377     if (NULL == additional_keys) {
00378         snmp_log(LOG_ERR, "could not create SN container for certificates\n");
00379         netsnmp_certs_shutdown();
00380         return;
00381     }
00382     additional_keys->container_name = strdup("certs_sn");
00383     additional_keys->free_item = NULL;
00384     additional_keys->compare = (netsnmp_container_compare*)_cert_sn_compare;
00385     additional_keys->ncompare = (netsnmp_container_compare*)_cert_sn_ncompare;
00386     netsnmp_container_add_index(_certs, additional_keys);
00387 
00389     additional_keys = netsnmp_container_find("certs_fn:binary_array");
00390     if (NULL == additional_keys) {
00391         snmp_log(LOG_ERR, "could not create FN container for certificates\n");
00392         netsnmp_certs_shutdown();
00393         return;
00394     }
00395     additional_keys->container_name = strdup("certs_fn");
00396     additional_keys->free_item = NULL;
00397     additional_keys->compare = (netsnmp_container_compare*)_cert_fn_compare;
00398     additional_keys->ncompare = (netsnmp_container_compare*)_cert_fn_ncompare;
00399     netsnmp_container_add_index(_certs, additional_keys);
00400 
00401     _keys = netsnmp_container_find("cert_keys:binary_array");
00402     if (NULL == _keys) {
00403         snmp_log(LOG_ERR, "could not create container for certificate keys\n");
00404         netsnmp_certs_shutdown();
00405         return;
00406     }
00407     _keys->container_name = strdup("netsnmp certificate keys");
00408     _keys->free_item = (netsnmp_container_obj_func*)_key_free;
00409     _keys->compare = (netsnmp_container_compare*)_cert_fn_compare;
00410 
00411     _setup_trusted_certs();
00412 }
00413 
00414 netsnmp_container *
00415 netsnmp_cert_map_container(void)
00416 {
00417     return _maps;
00418 }
00419 
00420 static netsnmp_cert *
00421 _new_cert(const char *dirname, const char *filename, int certType,
00422           int hashType, const char *fingerprint, const char *common_name,
00423           const char *subject)
00424 {
00425     netsnmp_cert    *cert;
00426 
00427     if ((NULL == dirname) || (NULL == filename)) {
00428         snmp_log(LOG_ERR, "bad parameters to _new_cert\n");
00429         return NULL;
00430     }
00431 
00432     cert = SNMP_MALLOC_TYPEDEF(netsnmp_cert);
00433     if (NULL == cert) {
00434         snmp_log(LOG_ERR,"could not allocate memory for certificate at %s/%s\n",
00435                  dirname, filename);
00436         return NULL;
00437     }
00438 
00439     DEBUGMSGT(("9:cert:struct:new","new cert 0x%#lx for %s\n", (u_long)cert,
00440                   filename));
00441 
00442     cert->info.dir = strdup(dirname);
00443     cert->info.filename = strdup(filename);
00444     cert->info.allowed_uses = NS_CERT_REMOTE_PEER;
00445     cert->info.type = certType;
00446     if (fingerprint) {
00447         cert->hash_type = hashType;
00448         cert->fingerprint = strdup(fingerprint);
00449     }
00450     if (common_name)
00451         cert->common_name = strdup(common_name);
00452     if (subject)
00453         cert->subject = strdup(subject);
00454 
00455     return cert;
00456 }
00457 
00458 static netsnmp_key *
00459 _new_key(const char *dirname, const char *filename)
00460 {
00461     netsnmp_key    *key;
00462     struct stat     fstat;
00463     char            fn[SNMP_MAXPATH];
00464 
00465     if ((NULL == dirname) || (NULL == filename)) {
00466         snmp_log(LOG_ERR, "bad parameters to _new_key\n");
00467         return NULL;
00468     }
00469 
00471     snprintf(fn, sizeof(fn), "%s/%s", dirname, filename);
00472     if (stat(fn, &fstat) != 0) {
00473         snmp_log(LOG_ERR, "could  not stat %s\n", fn);
00474         return NULL;
00475     }
00476 
00477     if ((fstat.st_mode & S_IROTH) || (fstat.st_mode & S_IROTH)) {
00478         snmp_log(LOG_ERR,
00479                  "refusing to read world readable or writable key %s\n", fn);
00480         return NULL;
00481     }
00482 
00483     key = SNMP_MALLOC_TYPEDEF(netsnmp_key);
00484     if (NULL == key) {
00485         snmp_log(LOG_ERR, "could not allocate memory for key at %s/%s\n",
00486                  dirname, filename);
00487         return NULL;
00488     }
00489 
00490     DEBUGMSGT(("cert:key:struct:new","new key 0x%#lx for %s\n", (u_long)key,
00491                filename));
00492 
00493     key->info.type = NS_CERT_TYPE_KEY;
00494     key->info.dir = strdup(dirname);
00495     key->info.filename = strdup(filename);
00496     key->info.allowed_uses = NS_CERT_IDENTITY;
00497 
00498     return key;
00499 }
00500 
00501 void
00502 netsnmp_cert_free(netsnmp_cert *cert)
00503 {
00504     if (NULL == cert)
00505         return;
00506 
00507     DEBUGMSGT(("9:cert:struct:free","freeing cert 0x%#lx, %s (fp %s; CN %s)\n",
00508                (u_long)cert, cert->info.filename ? cert->info.filename : "UNK",
00509                cert->fingerprint ? cert->fingerprint : "UNK",
00510                cert->common_name ? cert->common_name : "UNK"));
00511 
00512     SNMP_FREE(cert->info.dir);
00513     SNMP_FREE(cert->info.filename);
00514     SNMP_FREE(cert->subject);
00515     SNMP_FREE(cert->issuer);
00516     SNMP_FREE(cert->fingerprint);
00517     SNMP_FREE(cert->common_name);
00518     if (cert->ocert)
00519         X509_free(cert->ocert);
00520     if (cert->key && cert->key->cert == cert)
00521         cert->key->cert = NULL;
00522 
00523     free(cert); /* SNMP_FREE not needed on parameters */
00524 }
00525 
00526 void
00527 netsnmp_key_free(netsnmp_key *key)
00528 {
00529     if (NULL == key)
00530         return;
00531 
00532     DEBUGMSGT(("cert:key:struct:free","freeing key 0x%#lx, %s\n",
00533                (u_long)key, key->info.filename ? key->info.filename : "UNK"));
00534 
00535     SNMP_FREE(key->info.dir);
00536     SNMP_FREE(key->info.filename);
00537     EVP_PKEY_free(key->okey);
00538     if (key->cert && key->cert->key == key)
00539         key->cert->key = NULL;
00540 
00541     free(key); /* SNMP_FREE not needed on parameters */
00542 }
00543 
00544 static void
00545 _cert_free(netsnmp_cert *cert, void *context)
00546 {
00547     netsnmp_cert_free(cert);
00548 }
00549 
00550 static void
00551 _key_free(netsnmp_key *key, void *context)
00552 {
00553     netsnmp_key_free(key);
00554 }
00555 
00556 static int
00557 _cert_compare(netsnmp_cert *lhs, netsnmp_cert *rhs)
00558 {
00559     netsnmp_assert((lhs != NULL) && (rhs != NULL));
00560     netsnmp_assert((lhs->fingerprint != NULL) &&
00561                    (rhs->fingerprint != NULL));
00562 
00564     return strcmp(lhs->fingerprint, rhs->fingerprint);
00565 }
00566 
00567 static int
00568 _cert_path_compare(netsnmp_cert_common *lhs, netsnmp_cert_common *rhs)
00569 {
00570     int rc;
00571 
00572     netsnmp_assert((lhs != NULL) && (rhs != NULL));
00573     
00575     rc = strcmp(lhs->dir, rhs->dir);
00576     if (rc)
00577         return rc;
00578 
00580     return strcmp(lhs->filename, rhs->filename);
00581 }
00582 
00583 static int
00584 _cert_cn_compare(netsnmp_cert *lhs, netsnmp_cert *rhs)
00585 {
00586     int rc;
00587     const char *lhcn, *rhcn;
00588 
00589     netsnmp_assert((lhs != NULL) && (rhs != NULL));
00590 
00591     if (NULL == lhs->common_name)
00592         lhcn = "";
00593     else
00594         lhcn = lhs->common_name;
00595     if (NULL == rhs->common_name)
00596         rhcn = "";
00597     else
00598         rhcn = rhs->common_name;
00599 
00600     rc = strcmp(lhcn, rhcn);
00601     if (rc)
00602         return rc;
00603 
00605     return _cert_path_compare((netsnmp_cert_common*)lhs,
00606                               (netsnmp_cert_common*)rhs);
00607 }
00608 
00609 static int
00610 _cert_sn_compare(netsnmp_cert *lhs, netsnmp_cert *rhs)
00611 {
00612     int rc;
00613     const char *lhsn, *rhsn;
00614 
00615     netsnmp_assert((lhs != NULL) && (rhs != NULL));
00616 
00617     if (NULL == lhs->subject)
00618         lhsn = "";
00619     else
00620         lhsn = lhs->subject;
00621     if (NULL == rhs->subject)
00622         rhsn = "";
00623     else
00624         rhsn = rhs->subject;
00625 
00626     rc = strcmp(lhsn, rhsn);
00627     if (rc)
00628         return rc;
00629 
00631     return _cert_path_compare((netsnmp_cert_common*)lhs,
00632                               (netsnmp_cert_common*)rhs);
00633 }
00634 
00635 static int
00636 _cert_fn_compare(netsnmp_cert_common *lhs, netsnmp_cert_common *rhs)
00637 {
00638     int rc;
00639 
00640     netsnmp_assert((lhs != NULL) && (rhs != NULL));
00641 
00642     rc = strcmp(lhs->filename, rhs->filename);
00643     if (rc)
00644         return rc;
00645 
00647     return strcmp(lhs->dir, rhs->dir);
00648 }
00649 
00650 static int
00651 _cert_fn_ncompare(netsnmp_cert_common *lhs, netsnmp_cert_common *rhs)
00652 {
00653     netsnmp_assert((lhs != NULL) && (rhs != NULL));
00654     netsnmp_assert((lhs->filename != NULL) && (rhs->filename != NULL));
00655 
00656     return strncmp(lhs->filename, rhs->filename, strlen(rhs->filename));
00657 }
00658 
00659 static int
00660 _cert_sn_ncompare(netsnmp_cert *lhs, netsnmp_cert *rhs)
00661 {
00662     netsnmp_assert((lhs != NULL) && (rhs != NULL));
00663     netsnmp_assert((lhs->subject != NULL) && (rhs->subject != NULL));
00664 
00665     return strncmp(lhs->subject, rhs->subject, strlen(rhs->subject));
00666 }
00667 
00668 static int
00669 _cert_ext_type(const char *ext)
00670 {
00671     int rc = se_find_value_in_slist("cert_types", ext);
00672     if (SE_DNE == rc)
00673         return NS_CERT_TYPE_UNKNOWN;
00674     return rc;
00675 }
00676 
00677 static int
00678 _type_from_filename(const char *filename)
00679 {
00680     char     *pos;
00681     int       type;
00682 
00683     if (NULL == filename)
00684         return NS_CERT_TYPE_UNKNOWN;
00685 
00686     pos = strrchr(filename, '.');
00687     if (NULL == pos)
00688         return NS_CERT_TYPE_UNKNOWN;
00689 
00690     type = _cert_ext_type(++pos);
00691     return type;
00692 }
00693 
00694 /*
00695  * filter functions; return 1 to include file, 0 to exclude
00696  */
00697 static int
00698 _cert_cert_filter(const char *filename)
00699 {
00700     int  len = strlen(filename);
00701     const char *pos;
00702 
00703     if (len < 5) /* shortest name: x.YYY */
00704         return 0;
00705 
00706     pos = strrchr(filename, '.');
00707     if (NULL == pos)
00708         return 0;
00709 
00710     if (_cert_ext_type(++pos) != NS_CERT_TYPE_UNKNOWN)
00711         return 1;
00712 
00713     return 0;
00714 }
00715 
00716 /* #####################################################################
00717  *
00718  * cert index functions
00719  *
00720  * This code mimics what the mib index code does. The persistent
00721  * directory will have a subdirectory named 'cert_indexes'. Inside
00722  * this directory will be some number of files with ascii numeric
00723  * names (0, 1, 2, etc). Each of these files will start with a line
00724  * with the text "DIR ", followed by a directory name. The rest of the
00725  * file will be certificate fields and the certificate file name, one
00726  * certificate per line. The numeric file name is the integer 'directory
00727  * index'.
00728  */
00729 
00735 static int
00736 _certindex_add( const char *dirname, int i )
00737 {
00738     int rc;
00739     char *dirname_copy = strdup(dirname);
00740 
00741     if ( i == -1 ) {
00742         int max = se_find_free_value_in_list(_certindexes);
00743         if (SE_DNE == max)
00744             i = 0;
00745         else
00746             i = max;
00747     }
00748 
00749     DEBUGMSGT(("cert:index:add","dir %s at index %d\n", dirname, i ));
00750     rc = se_add_pair_to_list(&_certindexes, dirname_copy, i);
00751     if (SE_OK != rc) {
00752         snmp_log(LOG_ERR, "adding certindex dirname failed; "
00753                  "%d (%s) not added\n", i, dirname);
00754         free(dirname_copy);
00755         return -1;
00756     }
00757 
00758     return i;
00759 }
00760 
00766 static void
00767 _certindexes_load( void )
00768 {
00769     DIR *dir;
00770     struct dirent *file;
00771     FILE *fp;
00772     char filename[SNMP_MAXPATH], line[300];
00773     int  i;
00774     char *cp, *pos;
00775 
00776     /*
00777      * Open the CERT index directory, or create it (empty)
00778      */
00779     snprintf( filename, sizeof(filename), "%s/cert_indexes",
00780               get_persistent_directory());
00781     filename[sizeof(filename)-1] = 0;
00782     dir = opendir( filename );
00783     if ( dir == NULL ) {
00784         DEBUGMSGT(("cert:index:load",
00785                    "creating new cert_indexes directory\n"));
00786         mkdirhier( filename, NETSNMP_AGENT_DIRECTORY_MODE, 0);
00787         return;
00788     }
00789 
00790     /*
00791      * Create a list of which directory each file refers to
00792      */
00793     while ((file = readdir( dir ))) {
00794         if ( !isdigit(file->d_name[0]))
00795             continue;
00796         i = atoi( file->d_name );
00797 
00798         snprintf( filename, sizeof(filename), "%s/cert_indexes/%d",
00799               get_persistent_directory(), i );
00800         filename[sizeof(filename)-1] = 0;
00801         fp = fopen( filename, "r" );
00802         if ( !fp ) {
00803             DEBUGMSGT(("cert:index:load", "error opening index (%d)\n", i));
00804             fclose(fp);
00805             continue;
00806         }
00807         cp = fgets( line, sizeof(line), fp );
00808         if ( cp ) {
00809             line[strlen(line)-1] = 0;
00810             pos = strrchr(line, ' ');
00811             if (pos)
00812                 *pos = '\0';
00813             DEBUGMSGT(("9:cert:index:load","adding (%d) %s\n", i, line));
00814             (void)_certindex_add( line+4, i );  /* Skip 'DIR ' */
00815         } else {
00816             DEBUGMSGT(("cert:index:load", "Empty index (%d)\n", i));
00817         }
00818         fclose( fp );
00819     }
00820     closedir( dir );
00821 }
00822 
00828 static char *
00829 _certindex_lookup( const char *dirname )
00830 {
00831     int i;
00832     char filename[SNMP_MAXPATH];
00833 
00834 
00835     i = se_find_value_in_list(_certindexes, dirname);
00836     if (SE_DNE == i) {
00837         DEBUGMSGT(("9:cert:index:lookup","%s : (none)\n", dirname));
00838         return NULL;
00839     }
00840 
00841     snprintf(filename, sizeof(filename), "%s/cert_indexes/%d",
00842              get_persistent_directory(), i);
00843     filename[sizeof(filename)-1] = 0;
00844     DEBUGMSGT(("cert:index:lookup", "%s (%d) %s\n", dirname, i, filename ));
00845     return strdup(filename);
00846 }
00847 
00848 static FILE *
00849 _certindex_new( const char *dirname )
00850 {
00851     FILE *fp;
00852     char  filename[SNMP_MAXPATH], *cp;
00853     int   i;
00854 
00855     cp = _certindex_lookup( dirname );
00856     if (!cp) {
00857         i  = _certindex_add( dirname, -1 );
00858         if (-1 == i)
00859             return NULL; /* msg already logged */
00860         snprintf( filename, sizeof(filename), "%s/cert_indexes/%d",
00861                   get_persistent_directory(), i );
00862         filename[sizeof(filename)-1] = 0;
00863         cp = filename;
00864     }
00865     DEBUGMSGT(("9:cert:index:new", "%s (%s)\n", dirname, cp ));
00866     fp = fopen( cp, "w" );
00867     if (fp)
00868         fprintf( fp, "DIR %s %d\n", dirname, CERT_INDEX_FORMAT );
00869     else
00870         DEBUGMSGTL(("cert:index", "error opening new index file %s\n", dirname));
00871 
00872     if (cp != filename)
00873         free(cp);
00874 
00875     return fp;
00876 }
00877 
00878 /* #####################################################################
00879  *
00880  * certificate utility functions
00881  *
00882  */
00883 static X509 *
00884 netsnmp_ocert_get(netsnmp_cert *cert)
00885 {
00886     BIO            *certbio;
00887     X509           *ocert = NULL;
00888     EVP_PKEY       *okey = NULL;
00889     char            file[SNMP_MAXPATH];
00890     int             is_ca;
00891 
00892     if (NULL == cert)
00893         return NULL;
00894 
00895     if (cert->ocert)
00896         return cert->ocert;
00897 
00898     if (NS_CERT_TYPE_UNKNOWN == cert->info.type) {
00899         cert->info.type = _type_from_filename(cert->info.filename);
00900         if (NS_CERT_TYPE_UNKNOWN == cert->info.type) {
00901             snmp_log(LOG_ERR, "unknown certificate type %d for %s\n",
00902                      cert->info.type, cert->info.filename);
00903             return NULL;
00904         }
00905     }
00906 
00907     DEBUGMSGT(("9:cert:read", "Checking file %s\n", cert->info.filename));
00908 
00909     certbio = BIO_new(BIO_s_file());
00910     if (NULL == certbio) {
00911         snmp_log(LOG_ERR, "error creating BIO\n");
00912         return NULL;
00913     }
00914 
00915     snprintf(file, sizeof(file),"%s/%s", cert->info.dir, cert->info.filename);
00916     if (BIO_read_filename(certbio, file) <=0) {
00917         snmp_log(LOG_ERR, "error reading certificate %s into BIO\n", file);
00918         BIO_vfree(certbio);
00919         return NULL;
00920     }
00921 
00922     if (NS_CERT_TYPE_UNKNOWN == cert->info.type) {
00923         char *pos = strrchr(cert->info.filename, '.');
00924         if (NULL == pos)
00925             return NULL;
00926         cert->info.type = _cert_ext_type(++pos);
00927         netsnmp_assert(cert->info.type != NS_CERT_TYPE_UNKNOWN);
00928     }
00929 
00930     switch (cert->info.type) {
00931 
00932         case NS_CERT_TYPE_DER:
00933             ocert = d2i_X509_bio(certbio,NULL); /* DER/ASN1 */
00934             if (NULL != ocert)
00935                 break;
00936             (void)BIO_reset(certbio);
00939         case NS_CERT_TYPE_PEM:
00940             ocert = PEM_read_bio_X509_AUX(certbio, NULL, NULL, NULL);
00941             if (NULL == ocert)
00942                 break;
00943             if (NS_CERT_TYPE_DER == cert->info.type) {
00944                 DEBUGMSGT(("9:cert:read", "Changing type from DER to PEM\n"));
00945                 cert->info.type = NS_CERT_TYPE_PEM;
00946             }
00948             if (NULL == cert->key) {
00949                 (void)BIO_reset(certbio);
00950                 okey =  PEM_read_bio_PrivateKey(certbio, NULL, NULL, NULL);
00951                 if (NULL != okey) {
00952                     netsnmp_key  *key;
00953                     DEBUGMSGT(("cert:read:key", "found key with cert in %s\n",
00954                                cert->info.filename));
00955                     key = _new_key(cert->info.dir, cert->info.filename);
00956                     if (NULL != key) {
00957                         key->okey = okey;
00958                         if (-1 == CONTAINER_INSERT(_keys, key)) {
00959                             DEBUGMSGT(("cert:read:key:add",
00960                                        "error inserting key into container\n"));
00961                             netsnmp_key_free(key);
00962                             key = NULL;
00963                         }
00964                         else {
00965                             DEBUGMSGT(("cert:read:partner", "%s match found!\n",
00966                                        cert->info.filename));
00967                             key->cert = cert;
00968                             cert->key = key;
00969                             cert->info.allowed_uses |= NS_CERT_IDENTITY;
00970                         }
00971                     }
00972                 } /* null return from read */
00973             } /* null key */
00974             break;
00975 #ifdef CERT_PKCS12_SUPPORT_MAYBE_LATER
00976         case NS_CERT_TYPE_PKCS12:
00977             (void)BIO_reset(certbio);
00978             PKCS12 *p12 = d2i_PKCS12_bio(certbio, NULL);
00979             if ( (NULL != p12) && (PKCS12_verify_mac(p12, "", 0) ||
00980                                    PKCS12_verify_mac(p12, NULL, 0)))
00981                 PKCS12_parse(p12, "", NULL, &cert, NULL);
00982             break;
00983 #endif
00984         default:
00985             snmp_log(LOG_ERR, "unknown certificate type %d for %s\n",
00986                      cert->info.type, cert->info.filename);
00987     }
00988 
00989     BIO_vfree(certbio);
00990 
00991     if (NULL == ocert) {
00992         snmp_log(LOG_ERR, "error parsing certificate file %s\n",
00993                  cert->info.filename);
00994         return NULL;
00995     }
00996 
00997     cert->ocert = ocert;
00998     /*
00999      * X509_check_ca return codes:
01000      * 0 not a CA
01001      * 1 is a CA
01002      * 2 basicConstraints absent so "maybe" a CA
01003      * 3 basicConstraints absent but self signed V1.
01004      * 4 basicConstraints absent but keyUsage present and keyCertSign asserted.
01005      * 5 outdated Netscape Certificate Type CA extension.
01006      */
01007     is_ca = X509_check_ca(ocert);
01008     if (1 == is_ca)
01009         cert->info.allowed_uses |= NS_CERT_CA;
01010 
01011     if (NULL == cert->subject) {
01012         cert->subject = X509_NAME_oneline(X509_get_subject_name(ocert), NULL,
01013                                           0);
01014         DEBUGMSGT(("9:cert:add:subject", "subject name: %s\n", cert->subject));
01015     }
01016 
01017     if (NULL == cert->issuer) {
01018         cert->issuer = X509_NAME_oneline(X509_get_issuer_name(ocert), NULL, 0);
01019         if (strcmp(cert->subject, cert->issuer) == 0) {
01020             free(cert->issuer);
01021             cert->issuer = strdup("self-signed");
01022         }
01023         DEBUGMSGT(("9:cert:add:issuer", "CA issuer: %s\n", cert->issuer));
01024     }
01025     
01026     if (NULL == cert->fingerprint) {
01027         cert->hash_type = netsnmp_openssl_cert_get_hash_type(ocert);
01028         cert->fingerprint =
01029             netsnmp_openssl_cert_get_fingerprint(ocert, cert->hash_type);
01030     }
01031     
01032     if (NULL == cert->common_name) {
01033         cert->common_name =netsnmp_openssl_cert_get_commonName(ocert, NULL,
01034                                                                NULL);
01035         DEBUGMSGT(("9:cert:add:name","%s\n", cert->common_name));
01036     }
01037 
01038     return ocert;
01039 }
01040 
01041 EVP_PKEY *
01042 netsnmp_okey_get(netsnmp_key  *key)
01043 {
01044     BIO            *keybio;
01045     EVP_PKEY       *okey;
01046     char            file[SNMP_MAXPATH];
01047 
01048     if (NULL == key)
01049         return NULL;
01050 
01051     if (key->okey)
01052         return key->okey;
01053 
01054     snprintf(file, sizeof(file),"%s/%s", key->info.dir, key->info.filename);
01055     DEBUGMSGT(("cert:key:read", "Checking file %s\n", key->info.filename));
01056 
01057     keybio = BIO_new(BIO_s_file());
01058     if (NULL == keybio) {
01059         snmp_log(LOG_ERR, "error creating BIO\n");
01060         return NULL;
01061     }
01062 
01063     if (BIO_read_filename(keybio, file) <=0) {
01064         snmp_log(LOG_ERR, "error reading certificate %s into BIO\n",
01065                  key->info.filename);
01066         BIO_vfree(keybio);
01067         return NULL;
01068     }
01069 
01070     okey = PEM_read_bio_PrivateKey(keybio, NULL, NULL, NULL);
01071     if (NULL == okey)
01072         snmp_log(LOG_ERR, "error parsing certificate file %s\n",
01073                  key->info.filename);
01074     else
01075         key->okey = okey;
01076 
01077     BIO_vfree(keybio);
01078 
01079     return okey;
01080 }
01081 
01082 static netsnmp_cert *
01083 _find_issuer(netsnmp_cert *cert)
01084 {
01085     netsnmp_void_array *matching;
01086     netsnmp_cert       *candidate, *issuer = NULL;
01087     int                 i;
01088 
01089     if ((NULL == cert) || (NULL == cert->issuer))
01090         return NULL;
01091 
01094     matching = _cert_find_subset_sn(cert->issuer);
01095     if (NULL == matching)
01096         return NULL;
01097 
01099     for ( i=0; (NULL == issuer) && (i < matching->size); ++i) {
01101         candidate = (netsnmp_cert*)matching->array[i];
01102         if ((NULL == candidate->ocert) &&
01103             (netsnmp_ocert_get(candidate) == NULL))
01104             continue;
01105 
01107         if (netsnmp_openssl_cert_issued_by(candidate->ocert, cert->ocert))
01108             issuer = candidate;
01109     } 
01111     free(matching->array);
01112     free(matching);
01113 
01114     return issuer;
01115 }
01116 
01117 #define CERT_LOAD_OK       0
01118 #define CERT_LOAD_ERR     -1
01119 #define CERT_LOAD_PARTIAL -2
01120 int
01121 netsnmp_cert_load_x509(netsnmp_cert *cert)
01122 {
01123     int rc = CERT_LOAD_OK;
01124 
01126     if ((NULL == cert->ocert) && (netsnmp_ocert_get(cert) == NULL)) {
01127         DEBUGMSGT(("cert:load:err", "couldn't load cert for %s\n",
01128                    cert->info.filename));
01129         rc = CERT_LOAD_ERR;
01130     }
01131 
01133     if ((NULL != cert->key) && (NULL == cert->key->okey) &&
01134         (netsnmp_okey_get(cert->key) == NULL)) {
01135         DEBUGMSGT(("cert:load:err", "couldn't load key for cert %s\n",
01136                    cert->info.filename));
01137         rc = CERT_LOAD_ERR;
01138     }
01139 
01141     for (; cert && cert->issuer; cert = cert->issuer_cert) {
01143         if (strcmp(cert->issuer, "self-signed") == 0) {
01144             netsnmp_assert(cert->issuer_cert == NULL);
01145             break;
01146         }
01148         if (NULL == cert->issuer_cert) {
01149             cert->issuer_cert =  _find_issuer(cert);
01150             if (NULL == cert->issuer_cert) {
01151                 DEBUGMSGT(("cert:load:warn",
01152                            "couldn't load CA chain for cert %s\n",
01153                            cert->info.filename));
01154                 rc = CERT_LOAD_PARTIAL;
01155                 break;
01156             }
01157         }
01159         if ((NULL == cert->issuer_cert->ocert) &&
01160             (netsnmp_ocert_get(cert->issuer_cert) == NULL)) {
01161             DEBUGMSGT(("cert:load:warn", "couldn't load cert chain for %s\n",
01162                        cert->info.filename));
01163             rc = CERT_LOAD_PARTIAL;
01164             break;
01165         }
01166     } /* cert CA for loop */
01167 
01168     return rc;
01169 }
01170 
01171 static void
01172 _find_partner(netsnmp_cert *cert, netsnmp_key *key)
01173 {
01174     netsnmp_void_array *matching = NULL;
01175     char                filename[NAME_MAX], *pos;
01176 
01177     if ((cert && key) || (!cert && ! key)) {
01178         DEBUGMSGT(("cert:partner", "bad parameters searching for partner\n"));
01179         return;
01180     }
01181 
01182     snprintf(filename, sizeof(filename), "%s", key->info.filename);
01183     pos = strrchr(filename, '.');
01184     if (NULL == pos)
01185         return;
01186     *pos = 0;
01187 
01188     if(key) {
01189         if (key->cert) {
01190             DEBUGMSGT(("cert:partner", "key already has partner\n"));
01191             return;
01192         }
01193         DEBUGMSGT(("9:cert:partner", "%s looking for partner near %s\n",
01194                    key->info.filename, key->info.dir));
01195 
01196         matching = _cert_find_subset_fn( filename, key->info.dir );
01197         if (!matching)
01198             return;
01199         if (1 == matching->size) {
01200             cert = (netsnmp_cert*)matching->array[0];
01201             if (NULL == cert->key) {
01202                 DEBUGMSGT(("cert:partner", "%s match found!\n",
01203                            cert->info.filename));
01204                 key->cert = cert;
01205                 cert->key = key;
01206                 cert->info.allowed_uses |= NS_CERT_IDENTITY;
01207             }
01208             else if (cert->key != key)
01209                 snmp_log(LOG_ERR, "%s matching cert already has partner\n",
01210                          cert->info.filename);
01211         }
01212         else
01213             DEBUGMSGT(("cert:partner", "%s matches multiple certs\n",
01214                           key->info.filename));
01215     }
01216     else if(cert) {
01217         if (cert->key) {
01218             DEBUGMSGT(("cert:partner", "cert already has partner\n"));
01219             return;
01220         }
01221         DEBUGMSGT(("9:cert:partner", "%s looking for partner\n",
01222                    cert->info.filename));
01223 
01224         matching = _key_find_subset(filename);
01225         if (!matching)
01226             return;
01227         if (1 == matching->size) {
01228             key = (netsnmp_key*)matching->array[0];
01229             if (NULL == key->cert) {
01230                 DEBUGMSGT(("cert:partner", "%s found!\n", cert->info.filename));
01231                 key->cert = cert;
01232                 cert->key = key;
01233             }
01234             else if (key->cert != cert)
01235                 snmp_log(LOG_ERR, "%s matching key already has partner\n",
01236                          cert->info.filename);
01237         }
01238         else
01239             DEBUGMSGT(("cert:partner", "%s matches multiple keys\n",
01240                        cert->info.filename));
01241     }
01242     
01243     if (matching) {
01244         free(matching->array);
01245         free(matching);
01246     }
01247 }
01248 
01249 static int
01250 _add_certfile(const char* dirname, const char* filename, FILE *index)
01251 {
01252     X509         *ocert;
01253     EVP_PKEY     *okey;
01254     netsnmp_cert *cert = NULL;
01255     netsnmp_key  *key = NULL;
01256     char          certfile[SNMP_MAXPATH];
01257     int           type;
01258 
01259     if (((const void*)NULL == dirname) || (NULL == filename))
01260         return -1;
01261 
01262     type = _type_from_filename(filename);
01263     netsnmp_assert(type != NS_CERT_TYPE_UNKNOWN);
01264 
01265     snprintf(certfile, sizeof(certfile),"%s/%s", dirname, filename);
01266 
01267     DEBUGMSGT(("9:cert:file:add", "Checking file: %s (type %d)\n", filename,
01268                type));
01269 
01270     if (NS_CERT_TYPE_KEY == type) {
01271         key = _new_key(dirname, filename);
01272         if (NULL == key)
01273             return -1;
01274         okey = netsnmp_okey_get(key);
01275         if (NULL == okey) {
01276             netsnmp_key_free(key);
01277             return -1;
01278         }
01279         key->okey = okey;
01280         if (-1 == CONTAINER_INSERT(_keys, key)) {
01281             DEBUGMSGT(("cert:key:file:add:err",
01282                        "error inserting key into container\n"));
01283             netsnmp_key_free(key);
01284             key = NULL;
01285         }
01286     }
01287     else {
01288         cert = _new_cert(dirname, filename, type, -1, NULL, NULL, NULL);
01289         if (NULL == cert)
01290             return -1;
01291         ocert = netsnmp_ocert_get(cert);
01292         if (NULL == ocert) {
01293             netsnmp_cert_free(cert);
01294             return -1;
01295         }
01296         cert->ocert = ocert;
01297         if (-1 == CONTAINER_INSERT(_certs, cert)) {
01298             DEBUGMSGT(("cert:file:add:err",
01299                        "error inserting cert into container\n"));
01300             netsnmp_cert_free(cert);
01301             cert = NULL;
01302         }
01303     }
01304     if ((NULL == cert) && (NULL == key)) {
01305         DEBUGMSGT(("cert:file:add:failure", "for %s\n", certfile));
01306         return -1;
01307     }
01308 
01309     if (index) {
01313         if (cert)
01314             fprintf(index, "c:%s %d %d %s '%s' '%s'\n", filename,
01315                     cert->info.type, cert->hash_type, cert->fingerprint,
01316                     cert->common_name, cert->subject);
01317         else if (key)
01318             fprintf(index, "k:%s\n", filename);
01319     }
01320 
01321     return 0;
01322 }
01323 
01324 static int
01325 _cert_read_index(const char *dirname, struct stat *dirstat)
01326 {
01327     FILE           *index;
01328     char           *idxname, *pos;
01329     struct stat     idx_stat;
01330     char            tmpstr[SNMP_MAXPATH + 5], filename[NAME_MAX];
01331     char            fingerprint[60+1], common_name[64+1], type_str[15];
01332     char            subject[SNMP_MAXBUF_SMALL], hash_str[15];
01333     int             count = 0, type, hash, version;
01334     netsnmp_cert    *cert;
01335     netsnmp_key     *key;
01336     netsnmp_container *newer, *found;
01337 
01338     netsnmp_assert(NULL != dirname);
01339 
01340     idxname = _certindex_lookup( dirname );
01341     if (NULL == idxname) {
01342         DEBUGMSGT(("cert:index:parse", "no index for cert directory\n"));
01343         return -1;
01344     }
01345 
01346     /*
01347      * see if directory has been modified more recently than the index
01348      */
01349     if (stat(idxname, &idx_stat) != 0) {
01350         DEBUGMSGT(("cert:index:parse", "error getting index file stats\n"));
01351         SNMP_FREE(idxname);
01352         return -1;
01353     }
01354 
01355 #if (defined(WIN32) || defined(cygwin))
01356     /* For Win32 platforms, the directory does not maintain a last modification
01357      * date that we can compare with the modification date of the .index file.
01358      */
01359 #else
01360     if (dirstat->st_mtime >= idx_stat.st_mtime) {
01361         DEBUGMSGT(("cert:index:parse", "Index outdated; dir modified\n"));
01362         SNMP_FREE(idxname);
01363         return -1;
01364     }
01365 #endif
01366 
01367     /*
01368      * dir mtime doesn't change when files are touched, so we need to check
01369      * each file against the index in case a file has been modified.
01370      */
01371     newer =
01372         netsnmp_directory_container_read_some(NULL, dirname,
01373                                               (netsnmp_directory_filter*)
01374                                               _time_filter,(void*)&idx_stat,
01375                                               NETSNMP_DIR_NSFILE |
01376                                               NETSNMP_DIR_NSFILE_STATS);
01377     if (newer) {
01378         DEBUGMSGT(("cert:index:parse", "Index outdated; files modified\n"));
01379         CONTAINER_FREE_ALL(newer, NULL);
01380         CONTAINER_FREE(newer);
01381         SNMP_FREE(idxname);
01382         return -1;
01383     }
01384 
01385     DEBUGMSGT(("cert:index:parse", "The index for %s looks good\n", dirname));
01386 
01387     index = fopen(idxname, "r");
01388     if (NULL == index) {
01389         snmp_log(LOG_ERR, "cert:index:parse can't open index for %s\n",
01390             dirname);
01391         SNMP_FREE(idxname);
01392         return -1;
01393     }
01394 
01395     found = _get_cert_container(idxname);
01396 
01397     /*
01398      * check index format version
01399      */
01400     fgets(tmpstr, sizeof(tmpstr), index);
01401     pos = strrchr(tmpstr, ' ');
01402     if (pos) {
01403         ++pos;
01404         version = atoi(pos);
01405     }
01406     if ((NULL == pos) || (version != CERT_INDEX_FORMAT)) {
01407         DEBUGMSGT(("cert:index:add", "missing or wrong index format!\n"));
01408         fclose(index);
01409         SNMP_FREE(idxname);
01410         return -1;
01411     }
01412     while (1) {
01413         if (NULL == fgets(tmpstr, sizeof(tmpstr), index))
01414             break;
01415 
01416         if ('c' == tmpstr[0]) {
01417             pos = &tmpstr[2];
01418             if ((NULL == (pos=copy_nword(pos, filename, sizeof(filename)))) ||
01419                 (NULL == (pos=copy_nword(pos, type_str, sizeof(type_str)))) ||
01420                 (NULL == (pos=copy_nword(pos, hash_str, sizeof(hash_str)))) ||
01421                 (NULL == (pos=copy_nword(pos, fingerprint,
01422                                          sizeof(fingerprint)))) ||
01423                 (NULL == (pos=copy_nword(pos, common_name,
01424                                            sizeof(common_name)))) ||
01425                 (NULL != copy_nword(pos, subject, sizeof(subject)))) {
01426                 snmp_log(LOG_ERR, "_cert_read_index: error parsing line: %s\n",
01427                          tmpstr);
01428                 count = -1;
01429                 break;
01430             }
01431             type = atoi(type_str);
01432             hash = atoi(hash_str);
01433             cert = (void*)_new_cert(dirname, filename, type, hash, fingerprint,
01434                                     common_name, subject);
01435             if (cert && 0 == CONTAINER_INSERT(found, cert))
01436                 ++count;
01437             else {
01438                 DEBUGMSGT(("cert:index:add",
01439                            "error inserting cert into container\n"));
01440                 netsnmp_cert_free(cert);
01441                 cert = NULL;
01442             }
01443         }
01444         else if ('k' == tmpstr[0]) {
01445             if (NULL != copy_nword(&tmpstr[2], filename, sizeof(filename))) {
01446                 snmp_log(LOG_ERR, "_cert_read_index: error parsing line %s\n",
01447                     tmpstr);
01448                 continue;
01449             }
01450             key = _new_key(dirname, filename);
01451             if (key && 0 == CONTAINER_INSERT(_keys, key))
01452                 ++count;
01453             else {
01454                 DEBUGMSGT(("cert:index:add:key",
01455                            "error inserting key into container\n"));
01456                 netsnmp_key_free(key);
01457             }
01458         }
01459         else {
01460             snmp_log(LOG_ERR, "unknown line in cert index for %s\n", dirname);
01461             continue;
01462         }
01463     } /* while */
01464     fclose(index);
01465     SNMP_FREE(idxname);
01466 
01467     if (count > 0) {
01468         netsnmp_iterator  *itr = CONTAINER_ITERATOR(found);
01469         if (NULL == itr) {
01470             snmp_log(LOG_ERR, "could not get iterator for found certs\n");
01471             count = -1;
01472         }
01473         else {
01474             cert = ITERATOR_FIRST(itr);
01475             for( ; cert; cert = ITERATOR_NEXT(itr))
01476                 CONTAINER_INSERT(_certs, cert);
01477             ITERATOR_RELEASE(itr);
01478             DEBUGMSGT(("cert:index:parse","added %d certs from index\n",
01479                        count));
01480         }
01481     }
01482     if (count < 0)
01483         CONTAINER_FREE_ALL(found, NULL);
01484     CONTAINER_FREE(found);
01485 
01486     return count;
01487 }
01488 
01489 static int
01490 _add_certdir(const char *dirname)
01491 {
01492     FILE           *index;
01493     char           *file;
01494     int             count = 0;
01495     netsnmp_container *cert_container;
01496     netsnmp_iterator  *it;
01497     struct stat     statbuf;
01498 
01499     netsnmp_assert(NULL != dirname);
01500 
01501     DEBUGMSGT(("9:cert:dir:add", " config dir: %s\n", dirname ));
01502 
01503     if (stat(dirname, &statbuf) != 0) {
01504         DEBUGMSGT(("9:cert:dir:add", " dir not present: %s\n",
01505                    dirname ));
01506         return -1;
01507     }
01508 #ifdef S_ISDIR
01509     if (!S_ISDIR(statbuf.st_mode)) {
01510         DEBUGMSGT(("9:cert:dir:add", " not a dir: %s\n", dirname ));
01511         return -1;
01512     }
01513 #endif
01514 
01515     DEBUGMSGT(("cert:index:dir", "Scanning directory %s\n", dirname));
01516 
01517     /*
01518      * look for existing index
01519      */
01520     count = _cert_read_index(dirname, &statbuf);
01521     if (count >= 0)
01522         return count;
01523 
01524     index = _certindex_new( dirname );
01525     if (NULL == index) {
01526         DEBUGMSGT(("9:cert:index:dir",
01527                     "error opening index for cert directory\n"));
01528         DEBUGMSGTL(("cert:index", "could not open certificate index file\n"));
01529     }
01530 
01531     /*
01532      * index was missing, out of date or bad. rescan directory.
01533      */
01534     cert_container =
01535         netsnmp_directory_container_read_some(NULL, dirname,
01536                                               (netsnmp_directory_filter*)
01537                                               &_cert_cert_filter, NULL,
01538                                               NETSNMP_DIR_RELATIVE_PATH |
01539                                               NETSNMP_DIR_EMPTY_OK );
01540     if (NULL == cert_container) {
01541         DEBUGMSGT(("cert:index:dir",
01542                     "error creating container for cert files\n"));
01543         goto err_index;
01544     }
01545 
01546     /*
01547      * iterate through the found files and add them to index
01548      */
01549     it = CONTAINER_ITERATOR(cert_container);
01550     if (NULL == it) {
01551         DEBUGMSGT(("cert:index:dir",
01552                     "error creating iterator for cert files\n"));
01553         goto err_container;
01554     }
01555 
01556     for (file = ITERATOR_FIRST(it); file; file = ITERATOR_NEXT(it)) {
01557         DEBUGMSGT(("cert:index:dir", "adding %s to index\n", file));
01558         if ( 0 == _add_certfile( dirname, file, index ))
01559             count++;
01560         else
01561             DEBUGMSGT(("cert:index:dir", "error adding %s to index\n",
01562                         file));
01563     }
01564 
01565     /*
01566      * clean up and return
01567      */
01568     ITERATOR_RELEASE(it);
01569 
01570   err_container:
01571     netsnmp_directory_container_free(cert_container);
01572 
01573   err_index:
01574     if (index)
01575         fclose(index);
01576 
01577     return count;
01578 }
01579 
01580 static void
01581 _cert_indexes_load(void)
01582 {
01583     const char     *confpath;
01584     char           *confpath_copy, *dir, *st = NULL;
01585     char            certdir[SNMP_MAXPATH];
01586     const char     *subdirs[] = { NULL, "ca-certs", "certs", "private", NULL };
01587     int             i = 0;
01588 
01589     /*
01590      * load indexes from persistent dir
01591      */
01592     _certindexes_load();
01593 
01594     /*
01595      * duplicate path building from read_config_files_of_type() in
01596      * read_config.c. That is, use SNMPCONFPATH environment variable if
01597      * it is defined, otherwise use configuration directory.
01598      */
01599     confpath = netsnmp_getenv("SNMPCONFPATH");
01600     if (NULL == confpath)
01601         confpath = get_configuration_directory();
01602 
01603     subdirs[0] = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
01604                                        NETSNMP_DS_LIB_CERT_EXTRA_SUBDIR);
01605     confpath_copy = strdup(confpath);
01606     for ( dir = strtok_r(confpath_copy, ENV_SEPARATOR, &st);
01607           dir; dir = strtok_r(NULL, ENV_SEPARATOR, &st)) {
01608 
01609         i = (NULL == subdirs[0]) ? 1 : 0;
01610         for ( ; subdirs[i] ; ++i ) {
01612             snprintf(certdir, sizeof(certdir), "%s/tls/%s", dir, subdirs[i]);
01613             _add_certdir(certdir);
01614         } /* for subdirs */
01615     } /* for conf path dirs */
01616     SNMP_FREE(confpath_copy);
01617 }
01618 
01619 static void
01620 _cert_print(netsnmp_cert *c, void *context)
01621 {
01622     if (NULL == c)
01623         return;
01624 
01625     DEBUGMSGT(("cert:dump", "cert %s in %s\n", c->info.filename, c->info.dir));
01626     DEBUGMSGT(("cert:dump", "   type %d flags 0x%x (%s)\n",
01627              c->info.type, c->info.allowed_uses,
01628               _mode_str(c->info.allowed_uses)));
01629     DEBUGIF("9:cert:dump") {
01630         if (NS_CERT_TYPE_KEY != c->info.type) {
01631             if(c->subject) {
01632                 if (c->info.allowed_uses & NS_CERT_CA)
01633                     DEBUGMSGT(("9:cert:dump", "   CA: %s\n", c->subject));
01634                 else
01635                     DEBUGMSGT(("9:cert:dump", "   subject: %s\n", c->subject));
01636             }
01637             if(c->issuer)
01638                 DEBUGMSGT(("9:cert:dump", "   issuer: %s\n", c->issuer));
01639             if(c->fingerprint)
01640                 DEBUGMSGT(("9:cert:dump", "   fingerprint: %s(%d):%s\n",
01641                            se_find_label_in_slist("cert_hash_alg", c->hash_type),
01642                            c->hash_type, c->fingerprint));
01643         }
01644         /* netsnmp_feature_require(cert_utils_dump_names) */
01645         /* netsnmp_openssl_cert_dump_names(c->ocert); */
01646         netsnmp_openssl_cert_dump_extensions(c->ocert);
01647     }
01648     
01649 }
01650 
01651 static void
01652 _key_print(netsnmp_key *k, void *context)
01653 {
01654     if (NULL == k)
01655         return;
01656 
01657     DEBUGMSGT(("cert:dump", "key %s in %s\n", k->info.filename, k->info.dir));
01658     DEBUGMSGT(("cert:dump", "   type %d flags 0x%x (%s)\n", k->info.type,
01659               k->info.allowed_uses, _mode_str(k->info.allowed_uses)));
01660 }
01661 
01662 void
01663 netsnmp_cert_dump_all(void)
01664 {
01665     CONTAINER_FOR_EACH(_certs, (netsnmp_container_obj_func*)_cert_print, NULL);
01666     CONTAINER_FOR_EACH(_keys, (netsnmp_container_obj_func*)_key_print, NULL);
01667 }
01668 
01669 #ifdef CERT_MAIN
01670 /*
01671  * export BLD=~/net-snmp/build/ SRC=~/net-snmp/src 
01672  * 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
01673  *
01674  */
01675 int
01676 main(int argc, char** argv)
01677 {
01678     int          ch;
01679     extern char *optarg;
01680 
01681     while ((ch = getopt(argc, argv, "D:fHLMx:")) != EOF)
01682         switch(ch) {
01683             case 'D':
01684                 debug_register_tokens(optarg);
01685                 snmp_set_do_debugging(1);
01686                 break;
01687             default:
01688                 fprintf(stderr,"unknown option %c\n", ch);
01689         }
01690 
01691     init_snmp("dtlsapp");
01692 
01693     netsnmp_cert_dump_all();
01694 
01695     return 0;
01696 }
01697 
01698 #endif /* CERT_MAIN */
01699 
01700 static netsnmp_cert *_cert_find_fp(const char *fingerprint);
01701 
01702 void
01703 netsnmp_fp_lowercase_and_strip_colon(char *fp)
01704 {
01705     char *pos, *dest=NULL;
01706     
01707     if(!fp)
01708         return;
01709 
01711     for (pos = fp; *pos; ++pos ) {
01712         if (':' == *pos) {
01713             dest = pos;
01714             break;
01715         }
01716         else
01717             *pos = isalpha(*pos) ? tolower(*pos) : *pos;
01718     }
01719     if (!*pos)
01720         return;
01721 
01723     for (++pos; *pos; ++pos) {
01724         if (':' == *pos)
01725             continue;
01726         *dest++ = isalpha(*pos) ? tolower(*pos) : *pos;
01727     }
01728     *dest = *pos; /* nul termination */
01729 }
01730 
01731 netsnmp_cert *
01732 netsnmp_cert_find(int what, int where, void *hint)
01733 {
01734     netsnmp_cert *result = NULL;
01735     char         *fp, *hint_str;
01736 
01737     DEBUGMSGT(("cert:find:params", "looking for %s(%d) in %s(0x%x), hint %lu\n",
01738                _mode_str(what), what, _where_str(where), where, (u_long)hint));
01739 
01740     if (NS_CERTKEY_DEFAULT == where) {
01741             
01742         switch (what) {
01743             case NS_CERT_IDENTITY: /* want my ID */
01744                 fp =
01745                     netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
01746                                           NETSNMP_DS_LIB_TLS_LOCAL_CERT);
01748                 if (!fp) {
01749                     int           tmp;
01750                     tmp = (ptrdiff_t)hint;
01751                     DEBUGMSGT(("cert:find:params", " hint = %s\n",
01752                                tmp ? "server" : "client"));
01753                     fp =
01754                         netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, tmp ?
01755                                               NETSNMP_DS_LIB_X509_SERVER_PUB :
01756                                               NETSNMP_DS_LIB_X509_CLIENT_PUB );
01757                 }
01758                 if (!fp) {
01759                     /* As a special case, use the application type to
01760                        determine a file name to pull the default identity
01761                        from. */
01762                     return netsnmp_cert_find(what, NS_CERTKEY_FILE, netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE));
01763                 }
01764                 break;
01765             case NS_CERT_REMOTE_PEER:
01766                 fp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
01767                                            NETSNMP_DS_LIB_TLS_PEER_CERT);
01769                 if (!fp)
01770                     fp = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID,
01771                                                NETSNMP_DS_LIB_X509_SERVER_PUB);
01772                 break;
01773             default:
01774                 DEBUGMSGT(("cert:find:err", "unhandled type %d for %s(%d)\n",
01775                            what, _where_str(where), where));
01776                 return NULL;
01777         }
01778         if (fp)
01779             return netsnmp_cert_find(what, NS_CERTKEY_MULTIPLE, fp);
01780         return NULL;
01781     } /* where = ds store */
01782     else if (NS_CERTKEY_MULTIPLE == where) {
01783         /* tries multiple sources of certificates based on ascii lookup keys */
01784 
01785         /* Try a fingerprint match first, which should always be done first */
01786         /* (to avoid people naming filenames with conflicting FPs) */
01787         result = netsnmp_cert_find(what, NS_CERTKEY_FINGERPRINT, hint);
01788         if (!result) {
01789             /* Then try a file name lookup */
01790             result = netsnmp_cert_find(what, NS_CERTKEY_FILE, hint);
01791         }
01792     }
01793     else if (NS_CERTKEY_FINGERPRINT == where) {
01794         DEBUGMSGT(("cert:find:params", " hint = %s\n", (char *)hint));
01795         result = _cert_find_fp((char *)hint);
01796     }
01797     else if (NS_CERTKEY_TARGET_PARAM == where) {
01798         if (what != NS_CERT_IDENTITY) {
01799             snmp_log(LOG_ERR, "only identity is valid for target params\n");
01800             return NULL;
01801         }
01803         hint_str = (char *)hint;
01804         fp = _find_tlstmParams_fingerprint(hint_str);
01805         if (NULL != fp)
01806             result = _cert_find_fp(fp);
01807 
01808     }
01809     else if (NS_CERTKEY_TARGET_ADDR == where) {
01810         
01812         if (what != NS_CERT_REMOTE_PEER) {
01813             snmp_log(LOG_ERR, "only peer is valid for target addr\n");
01814             return NULL;
01815         }
01817         hint_str = (char *)hint;
01818         fp = _find_tlstmAddr_fingerprint(hint_str);
01819         if (NULL != fp)
01820             result = _cert_find_fp(fp);
01821 
01822     }
01823     else if (NS_CERTKEY_FILE == where) {
01825         char               *filename = (char*)hint;
01826         netsnmp_void_array *matching;
01827 
01828         DEBUGMSGT(("cert:find:params", " hint = %s\n", (char *)hint));
01829         matching = _cert_find_subset_fn( filename, NULL );
01830         if (!matching)
01831             return NULL;
01832         if (1 == matching->size)
01833             result = (netsnmp_cert*)matching->array[0];
01834         else {
01835             DEBUGMSGT(("cert:find:err", "%s matches multiple certs\n",
01836                        filename));
01837             result = NULL;
01838         }
01839         free(matching->array);
01840         free(matching);
01841     } /* where = NS_CERTKEY_FILE */
01842     else { /* unknown location */
01843         
01844         DEBUGMSGT(("cert:find:err", "unhandled location %d for %d\n", where,
01845                    what));
01846         return NULL;
01847     }
01848     
01849     if (NULL == result)
01850         return NULL;
01851 
01853     if (!(result->info.allowed_uses & what)) {
01854         DEBUGMSGT(("cert:find:err",
01855                    "cert %s / %s not allowed for %s(%d) (uses=%s (%d))\n",
01856                    result->info.filename, result->fingerprint, _mode_str(what),
01857                    what , _mode_str(result->info.allowed_uses),
01858                    result->info.allowed_uses));
01859         return NULL;
01860     }
01861     
01863     if (netsnmp_cert_load_x509(result) == CERT_LOAD_ERR)
01864         return NULL;
01865 
01866     DEBUGMSGT(("cert:find:found",
01867                "using cert %s / %s for %s(%d) (uses=%s (%d))\n",
01868                result->info.filename, result->fingerprint, _mode_str(what),
01869                what , _mode_str(result->info.allowed_uses),
01870                result->info.allowed_uses));
01871             
01872     return result;
01873 }
01874 
01875 #ifndef NETSNMP_FEATURE_REMOVE_CERT_FINGERPRINTS
01876 int
01877 netsnmp_cert_check_vb_fingerprint(const netsnmp_variable_list *var)
01878 {
01879     if (!var)
01880         return SNMP_ERR_GENERR;
01881 
01882     if (0 == var->val_len) /* empty allowed in some cases */
01883         return SNMP_ERR_NOERROR;
01884 
01885     if (! (0x01 & var->val_len)) { /* odd len */
01886         DEBUGMSGT(("cert:varbind:fingerprint",
01887                    "expecting odd length for fingerprint\n"));
01888         return SNMP_ERR_WRONGLENGTH;
01889     }
01890 
01891     if (var->val.string[0] > NS_HASH_MAX) {
01892         DEBUGMSGT(("cert:varbind:fingerprint", "hashtype %d > max %d\n",
01893                    var->val.string[0], NS_HASH_MAX));
01894         return SNMP_ERR_WRONGVALUE;
01895     }
01896 
01897     return SNMP_ERR_NOERROR;
01898 }
01899 
01906 int
01907 netsnmp_tls_fingerprint_parse(const u_char *binary_fp, int fp_len,
01908                               char **fp_str_ptr, u_int *fp_str_len, int realloc,
01909                               u_char *hash_type_ptr)
01910 {
01911     int     needed;
01912     size_t  fp_str_size;
01913 
01914     netsnmp_require_ptr_LRV( hash_type_ptr, SNMPERR_GENERR );
01915     netsnmp_require_ptr_LRV( fp_str_ptr, SNMPERR_GENERR );
01916     netsnmp_require_ptr_LRV( fp_str_len, SNMPERR_GENERR );
01917 
01918     /*
01919      * output string is binary fp length (minus 1 for initial hash type 
01920      * char) * 2 for bin to hex conversion, + 1 for null termination.
01921      */
01922     needed = ((fp_len - 1) * 2) + 1;
01923     if (*fp_str_len < needed) {
01924         DEBUGMSGT(("tls:fp:parse", "need %d bytes for output\n", needed ));
01925         return SNMPERR_GENERR;
01926     }
01927 
01928     /*
01929      * make sure hash type is in valid range
01930      */
01931     if ((0 == binary_fp[0]) || (binary_fp[0] > NS_HASH_MAX)) {
01932         DEBUGMSGT(("tls:fp:parse", "invalid hash type %d\n",
01933                    binary_fp[0]));
01934         return SNMPERR_GENERR;
01935     }
01936 
01937     /*
01938      * netsnmp_binary_to_hex allocate space for string, if needed
01939      */
01940     fp_str_size = *fp_str_len;
01941     *hash_type_ptr = binary_fp[0];
01942     netsnmp_binary_to_hex((u_char**)fp_str_ptr, &fp_str_size,
01943                           realloc, &binary_fp[1], fp_len - 1);
01944     *fp_str_len = fp_str_size;
01945     if (0 == *fp_str_len)
01946         return SNMPERR_GENERR;
01947 
01948     return SNMPERR_SUCCESS;
01949 }
01950 #endif /* NETSNMP_FEATURE_REMOVE_CERT_FINGERPRINTS */
01951 
01952 #ifndef NETSNMP_FEATURE_REMOVE_TLS_FINGERPRINT_BUILD
01953 
01960 int
01961 netsnmp_tls_fingerprint_build(int hash_type, const char *hex_fp,
01962                                    u_char **tls_fp, size_t *tls_fp_len,
01963                                    int realloc)
01964 {
01965     int     hex_fp_len, rc;
01966     size_t  tls_fp_size;
01967     size_t  offset;
01968 
01969     netsnmp_require_ptr_LRV( hex_fp, SNMPERR_GENERR );
01970     netsnmp_require_ptr_LRV( tls_fp, SNMPERR_GENERR );
01971     netsnmp_require_ptr_LRV( tls_fp_len, SNMPERR_GENERR );
01972 
01973     hex_fp_len = strlen(hex_fp);
01974     if (0 == hex_fp_len) {
01975         *tls_fp_len = 0;
01976         return SNMPERR_SUCCESS;
01977     }
01978 
01979     if ((hash_type <= NS_HASH_NONE) || (hash_type > NS_HASH_MAX)) {
01980         DEBUGMSGT(("tls:fp:build", "invalid hash type %d\n", hash_type ));
01981         return SNMPERR_GENERR;
01982     }
01983 
01984     /*
01985      * convert to binary
01986      */
01987     offset = 1;
01988     rc = netsnmp_hex_to_binary(tls_fp, &tls_fp_size, &offset, realloc, hex_fp,
01989                                ":");
01990     *tls_fp_len = tls_fp_size;
01991     if (rc != 1)
01992         return SNMPERR_GENERR;
01993     *tls_fp_len = offset;
01994     (*tls_fp)[0] = hash_type;
01995                                
01996     return SNMPERR_SUCCESS;
01997 }
01998 #endif /* NETSNMP_FEATURE_REMOVE_TLS_FINGERPRINT_BUILD */
01999 
02009 int
02010 netsnmp_cert_trust(SSL_CTX *ctx, netsnmp_cert *thiscert)
02011 {
02012     X509_STORE     *certstore;
02013     X509           *cert;
02014     
02015     /* ensure all needed pieces are present */
02016     netsnmp_assert_or_msgreturn(NULL != thiscert, "NULL certificate passed in",
02017                                 SNMPERR_GENERR);
02018     netsnmp_assert_or_msgreturn(NULL != thiscert->info.dir,
02019                                 "NULL certificate directory name passed in",
02020                                 SNMPERR_GENERR);
02021     netsnmp_assert_or_msgreturn(NULL != thiscert->info.filename,
02022                                 "NULL certificate filename name passed in",
02023                                 SNMPERR_GENERR);
02024 
02025     /* get the trusted certificate store and the certificate to load into it */
02026     certstore = SSL_CTX_get_cert_store(ctx);
02027     netsnmp_assert_or_msgreturn(NULL != certstore,
02028                                 "failed to get certificate trust store",
02029                                 SNMPERR_GENERR);
02030     cert = netsnmp_ocert_get(thiscert);
02031     netsnmp_assert_or_msgreturn(NULL != cert,
02032                                 "failed to get certificate from netsnmp_cert",
02033                                 SNMPERR_GENERR);
02034 
02035     /* Put the certificate into the store */
02036     DEBUGMSGTL(("cert:trust",
02037                 "putting trusted cert %p = %s in certstore %p\n", cert,
02038                 netsnmp_openssl_cert_get_fingerprint(cert, -1),
02039                 certstore));
02040     X509_STORE_add_cert(certstore, cert);
02041 
02042     return SNMPERR_SUCCESS;
02043 }
02044 
02055 int
02056 netsnmp_cert_trust_ca(SSL_CTX *ctx, netsnmp_cert *thiscert)
02057 {
02058     netsnmp_assert_or_msgreturn(NULL != thiscert, "NULL certificate passed in",
02059                                 SNMPERR_GENERR);
02060 
02061     /* find the root CA certificate in the chain */
02062     DEBUGMSGTL(("cert:trust_ca", "checking roots for %p \n", thiscert));
02063     while (thiscert->issuer_cert) {
02064         thiscert = thiscert->issuer_cert;
02065         DEBUGMSGTL(("cert:trust_ca", "  up one to %p\n", thiscert));
02066     }
02067 
02068     /* Add the found top lever certificate to the store */
02069     return netsnmp_cert_trust(ctx, thiscert);
02070 }
02071 
02072 netsnmp_container *
02073 netsnmp_cert_get_trustlist(void)
02074 {
02075     if (!_trusted_certs)
02076         _setup_trusted_certs();
02077     return _trusted_certs;
02078 }
02079 
02080 static void
02081 _parse_trustcert(const char *token, char *line)
02082 {
02083     if (!_trusted_certs)
02084         _setup_trusted_certs();
02085 
02086     if (!_trusted_certs)
02087         return;
02088 
02089     CONTAINER_INSERT(_trusted_certs, strdup(line));
02090 }
02091 
02092 /* ***************************************************************************
02093  *
02094  * mode text functions
02095  *
02096  */
02097 static const char *_mode_str(u_char mode)
02098 {
02099     return _modes[mode];
02100 }
02101 
02102 static const char *_where_str(u_int what)
02103 {
02104     switch (what) {
02105         case NS_CERTKEY_DEFAULT: return "DEFAULT";
02106         case NS_CERTKEY_FILE: return "FILE";
02107         case NS_CERTKEY_FINGERPRINT: return "FINGERPRINT";
02108         case NS_CERTKEY_MULTIPLE: return "MULTIPLE";
02109         case NS_CERTKEY_CA: return "CA";
02110         case NS_CERTKEY_SAN_RFC822: return "SAN_RFC822";
02111         case NS_CERTKEY_SAN_DNS: return "SAN_DNS";
02112         case NS_CERTKEY_SAN_IPADDR: return "SAN_IPADDR";
02113         case NS_CERTKEY_COMMON_NAME: return "COMMON_NAME";
02114         case NS_CERTKEY_TARGET_PARAM: return "TARGET_PARAM";
02115         case NS_CERTKEY_TARGET_ADDR: return "TARGET_ADDR";
02116     }
02117 
02118     return "UNKNOWN";
02119 }
02120 
02121 /* ***************************************************************************
02122  *
02123  * find functions
02124  *
02125  */
02126 static netsnmp_cert *
02127 _cert_find_fp(const char *fingerprint)
02128 {
02129     netsnmp_cert cert, *result = NULL;
02130     char         fp[EVP_MAX_MD_SIZE];
02131 
02132     if (NULL == fingerprint)
02133         return NULL;
02134 
02135     strncpy(fp, fingerprint, sizeof(fp));
02136     netsnmp_fp_lowercase_and_strip_colon(fp);
02137 
02139     memset(&cert, 0x00, sizeof(cert));
02140 
02141     cert.fingerprint = fp;
02142 
02143     result = CONTAINER_FIND(_certs,&cert);
02144     return result;
02145 }
02146 
02147 /*
02148  * reduce subset by eliminating any filenames that are longer than
02149  * the specified file name. e.g. 'snmp' would match 'snmp.key' and
02150  * 'snmpd.key'. We only want 'snmp.X', where X is a valid extension.
02151  */
02152 static void
02153 _reduce_subset(netsnmp_void_array *matching, const char *filename)
02154 {
02155     netsnmp_cert_common *cc;
02156     int i = 0, j, newsize, pos;
02157 
02158     if ((NULL == matching) || (NULL == filename))
02159         return;
02160 
02161     pos = strlen(filename);
02162     newsize = matching->size;
02163 
02164     for( ; i < matching->size; ) {
02165         /*
02166          * if we've shifted matches down we'll hit a NULL entry before
02167          * we hit the end of the array.
02168          */
02169         if (NULL == matching->array[i])
02170             break;
02171         /*
02172          * skip over valid matches. Note that we do not want to use
02173          * _type_from_filename.
02174          */
02175         cc = (netsnmp_cert_common*)matching->array[i];
02176         if (('.' == cc->filename[pos]) &&
02177             (NS_CERT_TYPE_UNKNOWN != _cert_ext_type(&cc->filename[pos+1]))) {
02178             ++i;
02179             continue;
02180         }
02181         /*
02182          * shrink array by shifting everything down a spot. Might not be
02183          * the most efficient soloution, but this is just happening at
02184          * startup and hopefully most certs won't have common prefixes.
02185          */
02186         --newsize;
02187         for ( j=i; j < newsize; ++j )
02188             matching->array[j] = matching->array[j+1];
02189         matching->array[j] = NULL;
02191     }
02192     /*
02193      * if we shifted, set the new size
02194      */
02195     if (newsize != matching->size) {
02196         DEBUGMSGT(("9:cert:subset:reduce", "shrank from %" NETSNMP_PRIz "d to %d\n",
02197                    matching->size, newsize));
02198         matching->size = newsize;
02199     }
02200 }
02201 
02202 /*
02203  * reduce subset by eliminating any filenames that are not under the
02204  * specified directory path.
02205  */
02206 static void
02207 _reduce_subset_dir(netsnmp_void_array *matching, const char *directory)
02208 {
02209     netsnmp_cert_common *cc;
02210     int                  i = 0, j, newsize, dir_len;
02211     char                 dir[SNMP_MAXPATH], *pos;
02212 
02213     if ((NULL == matching) || (NULL == directory))
02214         return;
02215 
02216     newsize = matching->size;
02217 
02218     /*
02219      * dir struct should be something like
02220      *          /usr/share/snmp/tls/certs
02221      *          /usr/share/snmp/tls/private
02222      *
02223      * so we want to backup up on directory for compares..
02224      */
02225     strncpy(dir,directory,sizeof(dir));
02226     pos = strrchr(dir, '/');
02227     if (NULL == pos) {
02228         DEBUGMSGTL(("cert:subset:dir", "no '/' in directory %s\n", directory));
02229         return;
02230     }
02231     *pos = '\0';
02232     dir_len = strlen(dir);
02233 
02234     for( ; i < matching->size; ) {
02235         /*
02236          * if we've shifted matches down we'll hit a NULL entry before
02237          * we hit the end of the array.
02238          */
02239         if (NULL == matching->array[i])
02240             break;
02241         /*
02242          * skip over valid matches. 
02243          */
02244         cc = (netsnmp_cert_common*)matching->array[i];
02245         if (strncmp(dir, cc->dir, dir_len) == 0) {
02246             ++i;
02247             continue;
02248         }
02249         /*
02250          * shrink array by shifting everything down a spot. Might not be
02251          * the most efficient soloution, but this is just happening at
02252          * startup and hopefully most certs won't have common prefixes.
02253          */
02254         --newsize;
02255         for ( j=i; j < newsize; ++j )
02256             matching->array[j] = matching->array[j+1];
02257         matching->array[j] = NULL;
02259     }
02260     /*
02261      * if we shifted, set the new size
02262      */
02263     if (newsize != matching->size) {
02264         DEBUGMSGT(("9:cert:subset:dir", "shrank from %" NETSNMP_PRIz "d to %d\n",
02265                    matching->size, newsize));
02266         matching->size = newsize;
02267     }
02268 }
02269 
02270 static netsnmp_void_array *
02271 _cert_find_subset_common(const char *filename, netsnmp_container *container)
02272 {
02273     netsnmp_cert_common   search;
02274     netsnmp_void_array   *matching;
02275 
02276     netsnmp_assert(filename && container);
02277 
02278     memset(&search, 0x00, sizeof(search));    /* clear search key */
02279 
02280     search.filename = NETSNMP_REMOVE_CONST(char*,filename);
02281 
02282     matching = CONTAINER_GET_SUBSET(container, &search);
02283     DEBUGMSGT(("9:cert:subset:found", "%" NETSNMP_PRIz "d matches\n", matching ?
02284                matching->size : 0));
02285     if (matching && matching->size > 1) {
02286         _reduce_subset(matching, filename);
02287         if (0 == matching->size) {
02288             free(matching->array);
02289             SNMP_FREE(matching);
02290         }
02291     }
02292     return matching;
02293 }
02294 
02295 static netsnmp_void_array *
02296 _cert_find_subset_fn(const char *filename, const char *directory)
02297 {
02298     netsnmp_container    *fn_container;
02299     netsnmp_void_array   *matching;
02300 
02302     fn_container = SUBCONTAINER_FIND(_certs, "certs_fn");
02303     netsnmp_assert(fn_container);
02304 
02305     matching = _cert_find_subset_common(filename, fn_container);
02306     if (matching && (matching->size > 1) && directory) {
02307         _reduce_subset_dir(matching, directory);
02308         if (0 == matching->size) {
02309             free(matching->array);
02310             SNMP_FREE(matching);
02311         }
02312     }
02313     return matching;
02314 }
02315 
02316 static netsnmp_void_array *
02317 _cert_find_subset_sn(const char *subject)
02318 {
02319     netsnmp_cert          search;
02320     netsnmp_void_array   *matching;
02321     netsnmp_container    *sn_container;
02322 
02324     sn_container = SUBCONTAINER_FIND(_certs, "certs_sn");
02325     netsnmp_assert(sn_container);
02326 
02327     memset(&search, 0x00, sizeof(search));    /* clear search key */
02328 
02329     search.subject = NETSNMP_REMOVE_CONST(char*,subject);
02330 
02331     matching = CONTAINER_GET_SUBSET(sn_container, &search);
02332     DEBUGMSGT(("9:cert:subset:found", "%" NETSNMP_PRIz "d matches\n", matching ?
02333                matching->size : 0));
02334     return matching;
02335 }
02336 
02337 static netsnmp_void_array *
02338 _key_find_subset(const char *filename)
02339 {
02340     return _cert_find_subset_common(filename, _keys);
02341 }
02342 
02344 static netsnmp_void_array *
02345 _find_subset_fp(netsnmp_container *certs, const char *fp)
02346 {
02347     netsnmp_cert_map    entry;
02348     netsnmp_container  *fp_container;
02349     netsnmp_void_array *va;
02350 
02351     if ((NULL == certs) || (NULL == fp))
02352         return NULL;
02353 
02354     fp_container = SUBCONTAINER_FIND(certs, "cert2sn_fp");
02355     netsnmp_assert_or_msgreturn(fp_container, "cert2sn_fp container missing",
02356                                 NULL);
02357 
02358     memset(&entry, 0x0, sizeof(entry));
02359 
02360     entry.fingerprint = NETSNMP_REMOVE_CONST(char*,fp);
02361 
02362     va = CONTAINER_GET_SUBSET(fp_container, &entry);
02363     return va;
02364 }
02365 
02366 #if 0  /* not used yet */
02367 static netsnmp_key *
02368 _key_find_fn(const char *filename)
02369 {
02370     netsnmp_key key, *result = NULL;
02371 
02372     netsnmp_assert(NULL != filename);
02373 
02374     memset(&key, 0x00, sizeof(key));    /* clear search key */
02375     key.info.filename = NETSNMP_REMOVE_CONST(char*,filename);
02376     result = CONTAINER_FIND(_keys,&key);
02377     return result;
02378 }
02379 #endif
02380 
02381 static int
02382 _time_filter(netsnmp_file *f, struct stat *idx)
02383 {
02385     if (f && idx && f->stats &&
02386         ((f->stats->st_mtime >= idx->st_mtime) ||
02387          (f->stats->st_ctime >= idx->st_mtime)))
02388         return NETSNMP_DIR_INCLUDE;
02389 
02390     return NETSNMP_DIR_EXCLUDE;
02391 }
02392 
02393 /* ***************************************************************************
02394  * ***************************************************************************
02395  *
02396  *
02397  * cert map functions
02398  *
02399  *
02400  * ***************************************************************************
02401  * ***************************************************************************/
02402 #define MAP_CONFIG_TOKEN "certSecName"
02403 static void _parse_map(const char *token, char *line);
02404 static void _map_free(netsnmp_cert_map* entry, void *ctx);
02405 static void _purge_config_entries(void);
02406 
02407 static void
02408 _init_tlstmCertToTSN(void)
02409 {
02410     const char *certSecName_help = MAP_CONFIG_TOKEN " PRIORITY FINGERPRINT "
02411         "[--shaNN|md5] <--sn SECNAME | --rfc822 | --dns | --ip | --cn | --any>";
02412 
02413     /*
02414      * container for cert to fingerprint mapping, with fingerprint key
02415      */
02416     _maps = netsnmp_cert_map_container_create(1);
02417 
02418     register_config_handler(NULL, MAP_CONFIG_TOKEN, _parse_map, _purge_config_entries,
02419                             certSecName_help);
02420 }
02421 
02422 netsnmp_cert_map *
02423 netsnmp_cert_map_alloc(char *fingerprint, X509 *ocert)
02424 {
02425     netsnmp_cert_map *cert_map = SNMP_MALLOC_TYPEDEF(netsnmp_cert_map);
02426     if (NULL == cert_map) {
02427         snmp_log(LOG_ERR, "could not allocate netsnmp_cert_map\n");
02428         return NULL;
02429     }
02430     
02431     if (fingerprint) {
02433         if (strlen(fingerprint) > (SNMPADMINLENGTH * 2)) {
02434             snmp_log(LOG_ERR, "fingerprint %s exceeds max length %d\n",
02435                      fingerprint, (SNMPADMINLENGTH * 2));
02436             free(cert_map);
02437             return NULL;
02438         }
02439         cert_map->fingerprint = strdup(fingerprint);
02440     }
02441     if (ocert) {
02442         cert_map->hashType = netsnmp_openssl_cert_get_hash_type(ocert);
02443         cert_map->ocert = ocert;
02444     }
02445 
02446     return cert_map;
02447 }
02448 
02449 void
02450 netsnmp_cert_map_free(netsnmp_cert_map *cert_map)
02451 {
02452     if (NULL == cert_map)
02453         return;
02454 
02455     SNMP_FREE(cert_map->fingerprint);
02456     SNMP_FREE(cert_map->data);
02458     free(cert_map); /* SNMP_FREE wasted on param */
02459 }
02460 
02461 int
02462 netsnmp_cert_map_add(netsnmp_cert_map *map)
02463 {
02464     int                rc;
02465 
02466     if (NULL == map)
02467         return -1;
02468 
02469     DEBUGMSGTL(("cert:map:add", "pri %d, fp %s\n",
02470                 map->priority, map->fingerprint));
02471 
02472     if ((rc = CONTAINER_INSERT(_maps, map)) != 0)
02473         snmp_log(LOG_ERR, "could not insert new certificate map");
02474 
02475     return rc;
02476 }
02477 
02478 #ifndef NETSNMP_FEATURE_REMOVE_CERT_MAP_REMOVE
02479 int
02480 netsnmp_cert_map_remove(netsnmp_cert_map *map)
02481 {
02482     int                rc;
02483 
02484     if (NULL == map)
02485         return -1;
02486 
02487     DEBUGMSGTL(("cert:map:remove", "pri %d, fp %s\n",
02488                 map->priority, map->fingerprint));
02489 
02490     if ((rc = CONTAINER_REMOVE(_maps, map)) != 0)
02491         snmp_log(LOG_ERR, "could not remove certificate map");
02492 
02493     return rc;
02494 }
02495 #endif /* NETSNMP_FEATURE_REMOVE_CERT_MAP_REMOVE */
02496 
02497 #ifndef NETSNMP_FEATURE_REMOVE_CERT_MAP_FIND
02498 netsnmp_cert_map *
02499 netsnmp_cert_map_find(netsnmp_cert_map *map)
02500 {
02501     if (NULL == map)
02502         return NULL;
02503 
02504     return CONTAINER_FIND(_maps, map);
02505 }
02506 #endif /* NETSNMP_FEATURE_REMOVE_CERT_MAP_FIND */
02507 
02508 static void
02509 _map_free(netsnmp_cert_map *map, void *context)
02510 {
02511     netsnmp_cert_map_free(map);
02512 }
02513 
02514 static int
02515 _map_compare(netsnmp_cert_map *lhs, netsnmp_cert_map *rhs)
02516 {
02517     netsnmp_assert((lhs != NULL) && (rhs != NULL));
02518 
02519     if (lhs->priority < rhs->priority)
02520         return -1;
02521     else if (lhs->priority > rhs->priority)
02522         return 1;
02523 
02524     return strcmp(lhs->fingerprint, rhs->fingerprint);
02525 }
02526 
02527 static int
02528 _map_fp_compare(netsnmp_cert_map *lhs, netsnmp_cert_map *rhs)
02529 {
02530     int rc;
02531     netsnmp_assert((lhs != NULL) && (rhs != NULL));
02532 
02533     if ((rc = strcmp(lhs->fingerprint, rhs->fingerprint)) != 0)
02534         return rc;
02535 
02536     if (lhs->priority < rhs->priority)
02537         return -1;
02538     else if (lhs->priority > rhs->priority)
02539         return 1;
02540 
02541     return 0;
02542 }
02543 
02544 static int
02545 _map_fp_ncompare(netsnmp_cert_map *lhs, netsnmp_cert_map *rhs)
02546 {
02547     netsnmp_assert((lhs != NULL) && (rhs != NULL));
02548 
02549     return strncmp(lhs->fingerprint, rhs->fingerprint,
02550                    strlen(rhs->fingerprint));
02551 }
02552 
02553 netsnmp_container *
02554 netsnmp_cert_map_container_create(int with_fp)
02555 {
02556     netsnmp_container *chain_map, *fp;
02557 
02558     chain_map = netsnmp_container_find("cert_map:stack:binary_array");
02559     if (NULL == chain_map) {
02560         snmp_log(LOG_ERR, "could not allocate container for cert_map\n");
02561         return NULL;
02562     }
02563 
02564     chain_map->container_name = strdup("cert_map");
02565     chain_map->free_item = (netsnmp_container_obj_func*)_map_free;
02566     chain_map->compare = (netsnmp_container_compare*)_map_compare;
02567 
02568     if (!with_fp)
02569         return chain_map;
02570 
02571     /*
02572      * add a secondary index to the table container
02573      */
02574     fp = netsnmp_container_find("cert2sn_fp:binary_array");
02575     if (NULL == fp) {
02576         snmp_log(LOG_ERR,
02577                  "error creating sub-container for tlstmCertToTSNTable\n");
02578         CONTAINER_FREE(chain_map);
02579         return NULL;
02580     }
02581     fp->container_name = strdup("cert2sn_fp");
02582     fp->compare = (netsnmp_container_compare*)_map_fp_compare;
02583     fp->ncompare = (netsnmp_container_compare*)_map_fp_ncompare;
02584     netsnmp_container_add_index(chain_map, fp);
02585 
02586     return chain_map;
02587 }
02588 
02589 int
02590 netsnmp_cert_parse_hash_type(const char *str)
02591 {
02592     int rc = se_find_value_in_slist("cert_hash_alg", str);
02593     if (SE_DNE == rc)
02594         return NS_HASH_NONE;
02595     return rc;
02596 }
02597 
02598 void
02599 netsnmp_cert_map_container_free(netsnmp_container *c)
02600 {
02601     if (NULL == c)
02602         return;
02603 
02604     CONTAINER_FREE_ALL(c, NULL);
02605     CONTAINER_FREE(c);
02606 }
02607 
02611 static void
02612 _purge_config_entries(void)
02613 {
02620     netsnmp_iterator   *itr;
02621     netsnmp_cert_map   *cert_map;
02622     netsnmp_container  *cert_maps = netsnmp_cert_map_container();
02623     netsnmp_container  *tmp_maps = NULL;
02624 
02625     if ((NULL == cert_maps) || (CONTAINER_SIZE(cert_maps) == 0))
02626         return;
02627 
02628     DEBUGMSGT(("cert:map:reconfig", "removing locally configured rows\n"));
02629     
02630     /*
02631      * duplicate cert_maps and then iterate over the copy. That way we can
02632      * add/remove to cert_maps without distrubing the iterator.
02633 xx
02634      */
02635     tmp_maps = CONTAINER_DUP(cert_maps, NULL, 0);
02636     if (NULL == tmp_maps) {
02637         snmp_log(LOG_ERR, "could not duplicate maps for reconfig\n");
02638         return;
02639     }
02640 
02641     itr = CONTAINER_ITERATOR(tmp_maps);
02642     if (NULL == itr) {
02643         snmp_log(LOG_ERR, "could not get iterator for reconfig\n");
02644         CONTAINER_FREE(tmp_maps);
02645         return;
02646     }
02647     cert_map = ITERATOR_FIRST(itr);
02648     for( ; cert_map; cert_map = ITERATOR_NEXT(itr)) {
02649 
02650         if (!(cert_map->flags & NSCM_FROM_CONFIG))
02651             continue;
02652 
02653         if (CONTAINER_REMOVE(cert_maps, cert_map) == 0)
02654             netsnmp_cert_map_free(cert_map);
02655     }
02656     ITERATOR_RELEASE(itr);
02657     CONTAINER_FREE(tmp_maps);
02658 
02659     return;
02660 }
02661 
02662 /*
02663   certSecName PRIORITY [--shaNN|md5] FINGERPRINT <--sn SECNAME | --rfc822 | --dns | --ip | --cn | --any>
02664 
02665   certSecName  100  ff:..11 --sn Wes
02666   certSecName  200  ee:..:22 --sn JohnDoe
02667   certSecName  300  ee:..:22 --rfc822
02668 */
02669 netsnmp_cert_map *
02670 netsnmp_certToTSN_parse_common(char **line)
02671 {
02672     netsnmp_cert_map *map;
02673     char             *tmp, buf[SNMP_MAXBUF_SMALL];
02674     size_t            len;
02675     netsnmp_cert     *tmpcert;
02676 
02677     if ((NULL == line) || (NULL == *line))
02678         return NULL;
02679 
02681     if (NULL == _maps) {
02682         NETSNMP_LOGONCE((LOG_ERR, "no container for certificate mappings\n"));
02683         return NULL;
02684     }
02685 
02686     DEBUGMSGT(("cert:util:config", "parsing %s\n", *line));
02687 
02688     /* read the priority */
02689     len = sizeof(buf);
02690     tmp = buf;
02691     *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
02692     tmp[len] = 0;
02693     if (!isdigit(tmp[0])) {
02694         netsnmp_config_error("could not parse priority");
02695         return NULL;
02696     }
02697     map = netsnmp_cert_map_alloc(NULL, NULL);
02698     if (NULL == map) {
02699         netsnmp_config_error("could not allocate cert map struct");
02700         return NULL;
02701     }
02702     map->flags |= NSCM_FROM_CONFIG;
02703     map->priority = atoi(buf);
02704 
02705     /* read the flag or the fingerprint */
02706     len = sizeof(buf);
02707     tmp = buf;
02708     *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
02709     tmp[len] = 0;
02710     if ((buf[0] == '-') && (buf[1] == '-')) {
02711         map->hashType = netsnmp_cert_parse_hash_type(&buf[2]);
02712         if (NS_HASH_NONE == map->hashType) {
02713             netsnmp_config_error("invalid hash type");
02714             goto end;
02715         }
02716 
02718         len = sizeof(buf);
02719         tmp = buf;
02720         *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
02721         tmp[len] = 0;
02722     }
02723     else
02724         map->hashType = NS_HASH_SHA1;
02725 
02726     /* look up the fingerprint */
02727     tmpcert = netsnmp_cert_find(NS_CERT_REMOTE_PEER, NS_CERTKEY_MULTIPLE, buf);
02728     if (NULL == tmpcert) {
02729         /* assume it's a raw fingerprint we don't have */
02730         netsnmp_fp_lowercase_and_strip_colon(buf);
02731         map->fingerprint = strdup(buf);
02732     } else {
02733         map->fingerprint =
02734             netsnmp_openssl_cert_get_fingerprint(tmpcert->ocert, -1);
02735     }
02736     
02737     if (NULL == *line) {
02738         netsnmp_config_error("must specify map type");
02739         goto end;
02740     }
02741 
02742     /* read the mapping type */
02743     len = sizeof(buf);
02744     tmp = buf;
02745     *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
02746     tmp[len] = 0;
02747     if ((buf[0] != '-') || (buf[1] != '-')) {
02748         netsnmp_config_error("unexpected fromat: %s\n", *line);
02749         goto end;
02750     }
02751     if (strcmp(&buf[2], "sn") == 0) {
02752         if (NULL == *line) {
02753             netsnmp_config_error("must specify secName for --sn");
02754             goto end;
02755         }
02756         len = sizeof(buf);
02757         tmp = buf;
02758         *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
02759         map->data = strdup(buf);
02760         if (map->data)
02761             map->mapType = TSNM_tlstmCertSpecified;
02762     }
02763     else if (strcmp(&buf[2], "cn") == 0)
02764         map->mapType = TSNM_tlstmCertCommonName;
02765     else if (strcmp(&buf[2], "ip") == 0)
02766         map->mapType = TSNM_tlstmCertSANIpAddress;
02767     else if (strcmp(&buf[2], "rfc822") == 0)
02768         map->mapType = TSNM_tlstmCertSANRFC822Name;
02769     else if (strcmp(&buf[2], "dns") == 0)
02770         map->mapType = TSNM_tlstmCertSANDNSName;
02771     else if (strcmp(&buf[2], "any") == 0)
02772         map->mapType = TSNM_tlstmCertSANAny;
02773     else
02774         netsnmp_config_error("unknown argument %s\n", buf);
02775     
02776   end:
02777     if (0 == map->mapType) {
02778         netsnmp_cert_map_free(map);
02779         map = NULL;
02780     }
02781 
02782     return map;
02783 }
02784 
02785 static void
02786 _parse_map(const char *token, char *line)
02787 {
02788     netsnmp_cert_map *map = netsnmp_certToTSN_parse_common(&line);
02789     if (NULL == map)
02790         return;
02791 
02792     if (netsnmp_cert_map_add(map) != 0) {
02793         netsnmp_cert_map_free(map);
02794         netsnmp_config_error(MAP_CONFIG_TOKEN
02795                              ": duplicate priority for certificate map");
02796     }
02797 }
02798 
02799 static int
02800 _fill_cert_map(netsnmp_cert_map *cert_map, netsnmp_cert_map *entry)
02801 {
02802     DEBUGMSGT(("cert:map:secname", "map: pri %d type %d data %s\n",
02803                entry->priority, entry->mapType, entry->data));
02804     cert_map->priority = entry->priority;
02805     cert_map->mapType = entry->mapType;
02806     cert_map->hashType = entry->hashType;
02807     if (entry->data) {
02808         cert_map->data = strdup(entry->data);
02809         if (NULL == cert_map->data ) {
02810             snmp_log(LOG_ERR, "secname map data dup failed\n");
02811             return -1;
02812         }
02813     }
02814 
02815     return 0;
02816 }
02817 
02818 /*
02819  * get secname map(s) for fingerprints
02820  */
02821 int
02822 netsnmp_cert_get_secname_maps(netsnmp_container *cert_maps)
02823 {
02824     netsnmp_iterator   *itr;
02825     netsnmp_cert_map   *cert_map, *new_cert_map, *entry;
02826     netsnmp_container  *new_maps = NULL;
02827     netsnmp_void_array *results;
02828     int                 j;
02829 
02830     if ((NULL == cert_maps) || (CONTAINER_SIZE(cert_maps) == 0))
02831         return -1;
02832 
02833     DEBUGMSGT(("cert:map:secname", "looking for matches for %" NETSNMP_PRIz "d fingerprints\n",
02834                CONTAINER_SIZE(cert_maps)));
02835     
02836     /*
02837      * duplicate cert_maps and then iterate over the copy. That way we can
02838      * add/remove to cert_maps without distrubing the iterator.
02839      */
02840     new_maps = CONTAINER_DUP(cert_maps, NULL, 0);
02841     if (NULL == new_maps) {
02842         snmp_log(LOG_ERR, "could not duplicate maps for secname mapping\n");
02843         return -1;
02844     }
02845 
02846     itr = CONTAINER_ITERATOR(new_maps);
02847     if (NULL == itr) {
02848         snmp_log(LOG_ERR, "could not get iterator for secname mappings\n");
02849         CONTAINER_FREE(new_maps);
02850         return -1;
02851     }
02852     cert_map = ITERATOR_FIRST(itr);
02853     for( ; cert_map; cert_map = ITERATOR_NEXT(itr)) {
02854 
02855         results = _find_subset_fp( netsnmp_cert_map_container(),
02856                                    cert_map->fingerprint );
02857         if (NULL == results) {
02858             DEBUGMSGT(("cert:map:secname", "no match for %s\n",
02859                        cert_map->fingerprint));
02860             if (CONTAINER_REMOVE(cert_maps, cert_map) != 0)
02861                 goto fail;
02862             continue;
02863         }
02864         DEBUGMSGT(("cert:map:secname", "%" NETSNMP_PRIz "d matches for %s\n",
02865                    results->size, cert_map->fingerprint));
02866         /*
02867          * first entry is a freebie
02868          */
02869         entry = (netsnmp_cert_map*)results->array[0];
02870         if (_fill_cert_map(cert_map, entry) != 0)
02871             goto fail;
02872 
02873         /*
02874          * additional entries must be allocated/inserted
02875          */
02876         if (results->size > 1) {
02877             for(j=1; j < results->size; ++j) {
02878                 entry = (netsnmp_cert_map*)results->array[j];
02879                 new_cert_map = netsnmp_cert_map_alloc(entry->fingerprint,
02880                                                       entry->ocert);
02881                 if (NULL == new_cert_map) {
02882                     snmp_log(LOG_ERR,
02883                              "could not allocate new cert map entry\n");
02884                     goto fail;
02885                 }
02886                 if (_fill_cert_map(new_cert_map, entry) != 0) {
02887                     netsnmp_cert_map_free(new_cert_map);
02888                     goto fail;
02889                 }
02890                 new_cert_map->ocert = cert_map->ocert;
02891                 if (CONTAINER_INSERT(cert_maps,new_cert_map) != 0) {
02892                     netsnmp_cert_map_free(new_cert_map);
02893                     goto fail;
02894                 }
02895             } /* for results */
02896         } /* results size > 1 */
02897 
02898         free(results->array);
02899         SNMP_FREE(results);
02900     }
02901     ITERATOR_RELEASE(itr);
02902     CONTAINER_FREE(new_maps);
02903 
02904     DEBUGMSGT(("cert:map:secname",
02905                "found %" NETSNMP_PRIz "d matches for fingerprints\n",
02906                CONTAINER_SIZE(cert_maps)));
02907     return 0;
02908 
02909   fail:
02910     if (results) {
02911         free(results->array);
02912         free(results);
02913     }
02914     ITERATOR_RELEASE(itr);
02915     CONTAINER_FREE(new_maps);
02916     return -1;
02917 }
02918 
02919 /* ***************************************************************************
02920  * ***************************************************************************
02921  *
02922  *
02923  * snmpTlstmParmsTable data
02924  *
02925  *
02926  * ***************************************************************************
02927  * ***************************************************************************/
02928 #define PARAMS_CONFIG_TOKEN "snmpTlstmParams"
02929 static void _parse_params(const char *token, char *line);
02930 
02931 static void
02932 _init_tlstmParams(void)
02933 {
02934     const char *params_help = 
02935         PARAMS_CONFIG_TOKEN " targetParamsName hashType:fingerPrint";
02936     
02937     /*
02938      * container for snmpTlstmParamsTable data
02939      */
02940     _tlstmParams = netsnmp_container_find("tlstmParams:string");
02941     if (NULL == _tlstmParams)
02942         snmp_log(LOG_ERR,
02943                  "error creating sub-container for tlstmParamsTable\n");
02944     else
02945         _tlstmParams->container_name = strdup("tlstmParams");
02946 
02947     register_config_handler(NULL, PARAMS_CONFIG_TOKEN, _parse_params, NULL,
02948                                 params_help);
02949 }
02950 
02951 #ifndef NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_CONTAINER
02952 netsnmp_container *
02953 netsnmp_tlstmParams_container(void)
02954 {
02955     return _tlstmParams;
02956 }
02957 #endif /* NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_CONTAINER */
02958 
02959 snmpTlstmParams *
02960 netsnmp_tlstmParams_create(const char *name, int hashType, const char *fp,
02961                            int fp_len)
02962 {
02963     snmpTlstmParams *stp = SNMP_MALLOC_TYPEDEF(snmpTlstmParams);
02964     if (NULL == stp)
02965         return NULL;
02966 
02967     if (name)
02968         stp->name = strdup(name);
02969     stp->hashType = hashType;
02970     if (fp)
02971         stp->fingerprint = strdup(fp);
02972     DEBUGMSGT(("9:tlstmParams:create", "0x%lx: %s\n", (u_long)stp,
02973                stp->name ? stp->name : "null"));
02974 
02975     return stp;
02976 }
02977 
02978 void
02979 netsnmp_tlstmParams_free(snmpTlstmParams *stp)
02980 {
02981     if (NULL == stp)
02982         return;
02983 
02984     DEBUGMSGT(("9:tlstmParams:release", "0x%lx %s\n", (u_long)stp,
02985                stp->name ? stp->name : "null"));
02986     SNMP_FREE(stp->name);
02987     SNMP_FREE(stp->fingerprint);
02988     free(stp); /* SNMP_FREE pointless on parameter */
02989 }
02990 
02991 snmpTlstmParams *
02992 netsnmp_tlstmParams_restore_common(char **line)
02993 {
02994     snmpTlstmParams  *stp;
02995     char             *tmp, buf[SNMP_MAXBUF_SMALL];
02996     size_t            len;
02997 
02998     if ((NULL == line) || (NULL == *line))
02999         return NULL;
03000 
03002     netsnmp_assert(_tlstmParams);
03003 
03004     stp = netsnmp_tlstmParams_create(NULL, 0, NULL, 0);
03005     if (NULL == stp)
03006         return NULL;
03007 
03009     len = sizeof(buf);
03010     tmp = buf;
03011     *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
03012     tmp[len] = 0;
03014     if (len)
03015         stp->name = strdup(buf);
03016 
03018     len = sizeof(buf);
03019     tmp = buf;
03020     *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
03021     tmp[len] = 0;
03022     if ((buf[0] == '-') && (buf[1] == '-')) {
03023         stp->hashType = netsnmp_cert_parse_hash_type(&buf[2]);
03024 
03026         len = sizeof(buf);
03027         tmp = buf;
03028         *line = read_config_read_octet_string(*line, (u_char **)&tmp, &len);
03029         tmp[len] = 0;
03030     }
03031     else
03032         stp->hashType =NS_HASH_SHA1;
03033     
03034     netsnmp_fp_lowercase_and_strip_colon(buf);
03035     stp->fingerprint = strdup(buf);
03036     stp->fingerprint_len = strlen(buf);
03037 
03038     DEBUGMSGTL(("tlstmParams:restore:common", "name '%s'\n", stp->name));
03039 
03040     return stp;
03041 }
03042 
03043 int
03044 netsnmp_tlstmParams_add(snmpTlstmParams *stp)
03045 {
03046     if (NULL == stp)
03047         return -1;
03048 
03049     DEBUGMSGTL(("tlstmParams:add", "adding entry 0x%lx %s\n", (u_long)stp,
03050                 stp->name));
03051 
03052     if (CONTAINER_INSERT(_tlstmParams, stp) != 0) {
03053         netsnmp_tlstmParams_free(stp);
03054         snmp_log(LOG_ERR, "error inserting tlstmParams %s", stp->name);
03055         return -1;
03056     }
03057 
03058     return 0;
03059 }
03060 
03061 #ifndef NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_REMOVE
03062 int
03063 netsnmp_tlstmParams_remove(snmpTlstmParams *stp)
03064 {
03065     if (NULL == stp)
03066         return -1;
03067 
03068     DEBUGMSGTL(("tlstmParams:remove", "removing entry 0x%lx %s\n", (u_long)stp,
03069                 stp->name));
03070 
03071     if (CONTAINER_REMOVE(_tlstmParams, stp) != 0) {
03072         snmp_log(LOG_ERR, "error removing tlstmParams %s", stp->name);
03073         return -1;
03074     }
03075 
03076     return 0;
03077 }
03078 #endif /* NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_REMOVE */
03079 
03080 #ifndef NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_FIND
03081 snmpTlstmParams *
03082 netsnmp_tlstmParams_find(snmpTlstmParams *stp)
03083 {
03084     snmpTlstmParams *found;
03085 
03086     if (NULL == stp)
03087         return NULL;
03088 
03089     found = CONTAINER_FIND(_tlstmParams, stp);
03090     return found;
03091 }
03092 #endif /* NETSNMP_FEATURE_REMOVE_TLSTMPARAMS_FIND */
03093 
03094 static void
03095 _parse_params(const char *token, char *line)
03096 {
03097     snmpTlstmParams *stp = netsnmp_tlstmParams_restore_common(&line);
03098 
03099     if (!stp)
03100         return;
03101 
03102     stp->flags = TLSTM_PARAMS_FROM_CONFIG | TLSTM_PARAMS_NONVOLATILE;
03103 
03104     netsnmp_tlstmParams_add(stp);
03105 }
03106 
03107 static char *
03108 _find_tlstmParams_fingerprint(const char *name)
03109 {
03110     snmpTlstmParams lookup_key, *result;
03111 
03112     if (NULL == name)
03113         return NULL;
03114 
03115     lookup_key.name = NETSNMP_REMOVE_CONST(char*, name);
03116 
03117     result = CONTAINER_FIND(_tlstmParams, &lookup_key);
03118     if ((NULL == result) || (NULL == result->fingerprint))
03119         return NULL;
03120 
03121     return strdup(result->fingerprint);
03122 }
03123 /*
03124  * END snmpTlstmParmsTable data
03125  * ***************************************************************************/
03126 
03127 /* ***************************************************************************
03128  * ***************************************************************************
03129  *
03130  *
03131  * snmpTlstmAddrTable data
03132  *
03133  *
03134  * ***************************************************************************
03135  * ***************************************************************************/
03136 #define ADDR_CONFIG_TOKEN "snmpTlstmAddr"
03137 static void _parse_addr(const char *token, char *line);
03138 
03139 static void
03140 _init_tlstmAddr(void)
03141 {
03142     const char *addr_help = 
03143         ADDR_CONFIG_TOKEN " targetAddrName hashType:fingerprint serverIdentity";
03144     
03145     /*
03146      * container for snmpTlstmAddrTable data
03147      */
03148     _tlstmAddr = netsnmp_container_find("tlstmAddr:string");
03149     if (NULL == _tlstmAddr)
03150         snmp_log(LOG_ERR,
03151                  "error creating sub-container for tlstmAddrTable\n");
03152     else
03153         _tlstmAddr->container_name = strdup("tlstmAddr");
03154 
03155     register_config_handler(NULL, ADDR_CONFIG_TOKEN, _parse_addr, NULL,
03156                             addr_help);
03157 }
03158 
03159 #ifndef NETSNMP_FEATURE_REMOVE_TLSTMADDR_CONTAINER
03160 netsnmp_container *
03161 netsnmp_tlstmAddr_container(void)
03162 {
03163     return _tlstmAddr;
03164 }
03165 #endif /* NETSNMP_FEATURE_REMOVE_TLSTMADDR_CONTAINER */
03166 
03167 /*
03168  * create a new row in the table 
03169  */
03170 snmpTlstmAddr *
03171 netsnmp_tlstmAddr_create(char *targetAddrName)
03172 {
03173     snmpTlstmAddr *entry;
03174 
03175     if (NULL == targetAddrName)
03176         return NULL;
03177 
03178     entry = SNMP_MALLOC_TYPEDEF(snmpTlstmAddr);
03179     if (!entry)
03180         return NULL;
03181 
03182     DEBUGMSGT(("tlstmAddr:entry:create", "entry %p %s\n", entry,
03183                targetAddrName ? targetAddrName : "NULL"));
03184 
03185     entry->name = strdup(targetAddrName);
03186 
03187     return entry;
03188 }
03189 
03190 void
03191 netsnmp_tlstmAddr_free(snmpTlstmAddr *entry)
03192 {
03193     if (!entry)
03194         return;
03195 
03196     SNMP_FREE(entry->name);
03197     SNMP_FREE(entry->fingerprint);
03198     SNMP_FREE(entry->identity);
03199     free(entry);
03200 }
03201 
03202 int
03203 netsnmp_tlstmAddr_restore_common(char **line, char *name, size_t *name_len,
03204                                  char *id, size_t *id_len, char *fp,
03205                                  size_t *fp_len, u_char *ht)
03206 {
03207     size_t fp_len_save = *fp_len;
03208 
03209     *line = read_config_read_octet_string(*line, (u_char **)&name, name_len);
03210     if (NULL == *line) {
03211         config_perror("incomplete line");
03212         return -1;
03213     }
03214     name[*name_len] = 0;
03215 
03216     *line = read_config_read_octet_string(*line, (u_char **)&fp, fp_len);
03217     if (NULL == *line) {
03218         config_perror("incomplete line");
03219         return -1;
03220     }
03221     fp[*fp_len] = 0;
03222     if ((fp[0] == '-') && (fp[1] == '-')) {
03223         *ht = netsnmp_cert_parse_hash_type(&fp[2]);
03224         
03226         *fp_len = fp_len_save;
03227         *line = read_config_read_octet_string(*line, (u_char **)&fp, fp_len);
03228         fp[*fp_len] = 0;
03229     }
03230     else
03231         *ht = NS_HASH_SHA1;
03232     netsnmp_fp_lowercase_and_strip_colon(fp);
03233     *fp_len = strlen(fp);
03234     
03235     *line = read_config_read_octet_string(*line, (u_char **)&id, id_len);
03236     id[*id_len] = 0;
03237     
03238     if (*ht <= NS_HASH_NONE || *ht > NS_HASH_MAX) {
03239         config_perror("invalid algorithm for fingerprint");
03240         return -1;
03241     }
03242 
03243     if ((0 == *fp_len) && ((0 == *id_len || (*id_len == 1 && id[0] == '*')))) {
03244         /*
03245          * empty fingerprint not allowed with '*' identity
03246          */
03247         config_perror("must specify fingerprint for '*' identity");
03248         return -1;
03249     }
03250 
03251     return 0;
03252 }
03253 
03254 int
03255 netsnmp_tlstmAddr_add(snmpTlstmAddr *entry)
03256 {
03257     if (!entry)
03258         return -1;
03259 
03260     DEBUGMSGTL(("tlstmAddr:add", "adding entry 0x%lx %s %s\n",
03261                 (u_long)entry, entry->name, entry->fingerprint));
03262     if (CONTAINER_INSERT(_tlstmAddr, entry) != 0) {
03263         netsnmp_tlstmAddr_free(entry);
03264         snmp_log(LOG_ERR, "could not insert addr %s", entry->name);
03265         return -1;
03266     }
03267 
03268     return 0;
03269 }
03270 
03271 #ifndef NETSNMP_FEATURE_REMOVE_TLSTMADDR_REMOVE
03272 int
03273 netsnmp_tlstmAddr_remove(snmpTlstmAddr *entry)
03274 {
03275     if (!entry)
03276         return -1;
03277 
03278     if (CONTAINER_REMOVE(_tlstmAddr, entry) != 0) {
03279         snmp_log(LOG_ERR, "could not remove addr %s", entry->name);
03280         return -1;
03281     }
03282 
03283     return 0;
03284 }
03285 #endif /* NETSNMP_FEATURE_REMOVE_TLSTMADDR_REMOVE */
03286 
03287 static void
03288 _parse_addr(const char *token, char *line)
03289 {
03290     snmpTlstmAddr *entry;
03291     char           name[SNMPADMINLENGTH  + 1], id[SNMPADMINLENGTH  + 1],
03292                    fingerprint[SNMPTLSFINGERPRINT_MAX_LEN + 1];
03293     size_t         name_len = sizeof(name), id_len = sizeof(id),
03294                    fp_len = sizeof(fingerprint);
03295     u_char         hashType;
03296     int            rc;
03297 
03298     rc = netsnmp_tlstmAddr_restore_common(&line, name, &name_len, id, &id_len,
03299                                           fingerprint, &fp_len, &hashType);
03300     if (rc < 0)
03301         return;
03302 
03303     if (NULL != line)
03304         config_pwarn("ignore extra tokens on line");
03305 
03306     entry = netsnmp_tlstmAddr_create(name);
03307     if (NULL == entry)
03308         return;
03309 
03310     entry->flags |= TLSTM_ADDR_FROM_CONFIG;
03311     entry->hashType = hashType;
03312     if (fp_len)
03313         entry->fingerprint = strdup(fingerprint);
03314     if (id_len)
03315         entry->identity = strdup(id);
03316 
03317     if (netsnmp_tlstmAddr_add(entry) != 0)
03318         netsnmp_tlstmAddr_free(entry);
03319 
03320     return;
03321 }
03322 
03323 static char *
03324 _find_tlstmAddr_fingerprint(const char *name)
03325 {
03326     snmpTlstmAddr    lookup_key, *result;
03327 
03328     if (NULL == name)
03329         return NULL;
03330 
03331     lookup_key.name = NETSNMP_REMOVE_CONST(char*, name);
03332 
03333     result = CONTAINER_FIND(_tlstmAddr, &lookup_key);
03334     if (NULL == result)
03335         return NULL;
03336 
03337     return result->fingerprint;
03338 }
03339 
03340 #ifndef NETSNMP_FEATURE_REMOVE_TLSTMADDR_GET_SERVERID
03341 char *
03342 netsnmp_tlstmAddr_get_serverId(const char *name)
03343 {
03344     snmpTlstmAddr    lookup_key, *result;
03345 
03346     if (NULL == name)
03347         return NULL;
03348 
03349     lookup_key.name = NETSNMP_REMOVE_CONST(char*, name);
03350 
03351     result = CONTAINER_FIND(_tlstmAddr, &lookup_key);
03352     if (NULL == result)
03353         return NULL;
03354 
03355     return result->identity;
03356 }
03357 #endif /* NETSNMP_FEATURE_REMOVE_TLSTMADDR_GET_SERVERID */
03358 /*
03359  * END snmpTlstmAddrTable data
03360  * ***************************************************************************/
03361 
03362 #else
03363 netsnmp_feature_unused(cert_util);
03364 #endif /* NETSNMP_FEATURE_REMOVE_CERT_UTIL */
03365 netsnmp_feature_unused(cert_util);
03366 #endif /* defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) */