net-snmp 5.7
snmp_openssl.c
00001 /*
00002  * snmp_openssl.c
00003  */
00004 
00005 #include <net-snmp/net-snmp-config.h>
00006 
00007 #include <net-snmp/net-snmp-includes.h>
00008 
00009 #include <net-snmp/net-snmp-features.h>
00010 
00011 #if defined(NETSNMP_USE_OPENSSL) && defined(HAVE_LIBSSL) && !defined(NETSNMP_FEATURE_REMOVE_CERT_UTIL)
00012 
00013 netsnmp_feature_require(container_free_all)
00014 
00015 netsnmp_feature_child_of(openssl_cert_get_subjectAltNames, netsnmp_unused)
00016 netsnmp_feature_child_of(openssl_ht2nid, netsnmp_unused)
00017 netsnmp_feature_child_of(openssl_err_log, netsnmp_unused)
00018 netsnmp_feature_child_of(cert_dump_names, netsnmp_unused)
00019 
00020 #include <ctype.h>
00021 
00022 #include <openssl/evp.h>
00023 #include <openssl/ssl.h>
00024 #include <openssl/x509.h>
00025 #include <openssl/x509v3.h>
00026 #include <openssl/err.h>
00027 #include <openssl/objects.h>
00028 
00029 #include <net-snmp/library/snmp_debug.h>
00030 #include <net-snmp/library/cert_util.h>
00031 #include <net-snmp/library/snmp_openssl.h>
00032 
00033 static u_char have_started_already = 0;
00034 
00035 /*
00036  * This code merely does openssl initialization so that multilpe
00037  * modules are safe to call netsnmp_init_openssl() for bootstrapping
00038  * without worrying about other callers that may have already done so.
00039  */
00040 void netsnmp_init_openssl(void) {
00041 
00042     /* avoid duplicate calls */
00043     if (have_started_already)
00044         return;
00045     have_started_already = 1;
00046 
00047     DEBUGMSGTL(("snmp_openssl", "initializing\n"));
00048 
00049     /* Initializing OpenSSL */
00050     SSL_library_init();
00051     SSL_load_error_strings();
00052     ERR_load_BIO_strings();
00053     OpenSSL_add_all_algorithms();
00054 }
00055 
00061 static char *
00062 _cert_get_name(X509 *ocert, int which, char **buf, int *len, int flags)
00063 {
00064     X509_NAME       *osubj_name;
00065     int              space;
00066     char            *buf_ptr;
00067 
00068     if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
00069         return NULL;
00070 
00071     osubj_name = X509_get_subject_name(ocert);
00072     if (NULL == osubj_name) {
00073         DEBUGMSGT(("openssl:cert:name", "no subject name!\n"));
00074         return NULL;
00075     }
00076 
00078     space = X509_NAME_get_text_by_NID(osubj_name, which, NULL, 0);
00079     if (-1 == space)
00080         return NULL;
00081     ++space; /* for NUL */
00082     if (buf && *buf) {
00083         if (*len < space)
00084             return NULL;
00085         buf_ptr = *buf;
00086     }
00087     else {
00088         buf_ptr = calloc(1,space);
00089         if (!buf_ptr)
00090             return NULL;
00091     }
00092     space = X509_NAME_get_text_by_NID(osubj_name, which, buf_ptr, space);
00093     if (len)
00094         *len = space;
00095 
00096     return buf_ptr;
00097 }
00098 
00101 char *
00102 netsnmp_openssl_cert_get_subjectName(X509 *ocert, char **buf, int *len)
00103 {
00104     X509_NAME       *osubj_name;
00105     int              space;
00106     char            *buf_ptr;
00107 
00108     if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
00109         return NULL;
00110 
00111     osubj_name = X509_get_subject_name(ocert);
00112     if (NULL == osubj_name) {
00113         DEBUGMSGT(("openssl:cert:name", "no subject name!\n"));
00114         return NULL;
00115     }
00116 
00117     if (buf) {
00118         buf_ptr = *buf;
00119         space = *len;
00120     }
00121     else {
00122         buf_ptr = NULL;
00123         space = 0;
00124     }
00125     buf_ptr = X509_NAME_oneline(osubj_name, buf_ptr, space);
00126     if (len)
00127         *len = strlen(buf_ptr);
00128 
00129     return buf_ptr;
00130 }
00131 
00137 char *
00138 netsnmp_openssl_cert_get_commonName(X509 *ocert, char **buf, int *len)
00139 {
00140     return _cert_get_name(ocert, NID_commonName, buf, len, 0);
00141 }
00142 
00143 #ifndef NETSNMP_FEATURE_REMOVE_CERT_DUMP_NAMES
00144 
00146 void
00147 netsnmp_openssl_cert_dump_names(X509 *ocert)
00148 {
00149     int              i, onid;
00150     X509_NAME_ENTRY *oname_entry;
00151     X509_NAME       *osubj_name;
00152     const char      *prefix_short, *prefix_long;
00153 
00154     if (NULL == ocert)
00155         return;
00156 
00157     osubj_name = X509_get_subject_name(ocert);
00158     if (NULL == osubj_name) {
00159         DEBUGMSGT(("9:cert:dump:names", "no subject name!\n"));
00160         return;
00161     }
00162 
00163     for (i = 0; i < X509_NAME_entry_count(osubj_name); i++) {
00164         oname_entry = X509_NAME_get_entry(osubj_name, i);
00165         netsnmp_assert(NULL != oname_entry);
00166 
00167         if (oname_entry->value->type != V_ASN1_PRINTABLESTRING)
00168             continue;
00169 
00171         onid = OBJ_obj2nid(oname_entry->object);
00172         if (onid == NID_undef) {
00173             prefix_long = prefix_short = "UNKNOWN";
00174         }
00175         else {
00176             prefix_long = OBJ_nid2ln(onid);
00177             prefix_short = OBJ_nid2sn(onid);
00178         }
00179 
00180         DEBUGMSGT(("9:cert:dump:names",
00181                    "[%02d] NID type %d, ASN type %d\n", i, onid,
00182                    oname_entry->value->type));
00183         DEBUGMSGT(("9:cert:dump:names", "%s/%s: '%s'\n", prefix_long,
00184                    prefix_short, ASN1_STRING_data(oname_entry->value)));
00185     }
00186 }
00187 #endif /* NETSNMP_FEATURE_REMOVE_CERT_DUMP_NAMES */
00188 
00189 static char *
00190 _cert_get_extension(X509_EXTENSION  *oext, char **buf, int *len, int flags)
00191 {
00192     int              space;
00193     char            *buf_ptr = NULL;
00194     u_char          *data;
00195     BIO             *bio;
00196     
00197     if ((NULL == oext) || ((buf && !len) || (len && !buf)))
00198         return NULL;
00199 
00200     bio = BIO_new(BIO_s_mem());
00201     if (NULL == bio) {
00202         snmp_log(LOG_ERR, "could not get bio for extension\n");
00203         return NULL;
00204     }
00205     if (X509V3_EXT_print(bio, oext, 0, 0) != 1) {
00206         snmp_log(LOG_ERR, "could not print extension!\n");
00207         BIO_vfree(bio);
00208         return NULL;
00209     }
00210 
00211     space = BIO_get_mem_data(bio, &data);
00212     if (buf && *buf) {
00213         if (*len < space) 
00214             buf_ptr = NULL;
00215         else
00216             buf_ptr = *buf;
00217     }
00218     else
00219         buf_ptr = calloc(1,space + 1);
00220     
00221     if (!buf_ptr) {
00222         snmp_log(LOG_ERR,
00223                  "not enough space or error in allocation for extenstion\n");
00224         BIO_vfree(bio);
00225         return NULL;
00226     }
00227     memcpy(buf_ptr, data, space);
00228     buf_ptr[space] = 0;
00229     if (len)
00230         *len = space;
00231 
00232     BIO_vfree(bio);
00233 
00234     return buf_ptr;
00235 }
00236 
00242 X509_EXTENSION  *
00243 _cert_get_extension_at(X509 *ocert, int pos, char **buf, int *len, int flags)
00244 {
00245     X509_EXTENSION  *oext;
00246 
00247     if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
00248         return NULL;
00249 
00250     oext = X509_get_ext(ocert,pos);
00251     if (NULL == oext) {
00252         snmp_log(LOG_ERR, "extension number %d not found!\n", pos);
00253         netsnmp_openssl_cert_dump_extensions(ocert);
00254         return NULL;
00255     }
00256 
00257     return oext;
00258 }
00259 
00265 static char *
00266 _cert_get_extension_str_at(X509 *ocert, int pos, char **buf, int *len,
00267                            int flags)
00268 {
00269     X509_EXTENSION  *oext;
00270 
00271     if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
00272         return NULL;
00273 
00274     oext = X509_get_ext(ocert,pos);
00275     if (NULL == oext) {
00276         snmp_log(LOG_ERR, "extension number %d not found!\n", pos);
00277         netsnmp_openssl_cert_dump_extensions(ocert);
00278         return NULL;
00279     }
00280 
00281     return _cert_get_extension(oext, buf, len, flags);
00282 }
00283 
00289 X509_EXTENSION *
00290 _cert_get_extension_id(X509 *ocert, int which, char **buf, int *len, int flags)
00291 {
00292     int pos;
00293 
00294     if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
00295         return NULL;
00296 
00297     pos = X509_get_ext_by_NID(ocert,which,-1);
00298     if (pos < 0) {
00299         DEBUGMSGT(("openssl:cert:name", "no extension %d\n", which));
00300         return NULL;
00301     }
00302 
00303     return _cert_get_extension_at(ocert, pos, buf, len, flags);
00304 }
00305 
00311 static char *
00312 _cert_get_extension_id_str(X509 *ocert, int which, char **buf, int *len,
00313                            int flags)
00314 {
00315     int pos;
00316 
00317     if ((NULL == ocert) || ((buf && !len) || (len && !buf)))
00318         return NULL;
00319 
00320     pos = X509_get_ext_by_NID(ocert,which,-1);
00321     if (pos < 0) {
00322         DEBUGMSGT(("openssl:cert:name", "no extension %d\n", which));
00323         return NULL;
00324     }
00325 
00326     return _cert_get_extension_str_at(ocert, pos, buf, len, flags);
00327 }
00328 
00329 static char *
00330 _extract_oname(const GENERAL_NAME *oname)
00331 {
00332     char  ipbuf[60], *buf = NULL, *rtn = NULL;
00333 
00334     if (NULL == oname)
00335         return NULL;
00336 
00337     switch ( oname->type ) {
00338         case GEN_EMAIL:
00339         case GEN_DNS:
00340             /*case GEN_URI:*/
00341             ASN1_STRING_to_UTF8((unsigned char**)&buf, oname->d.ia5);
00342             if (buf)
00343                 rtn = strdup(buf);
00344             break;
00345 
00346         case GEN_IPADD:
00347             if (oname->d.iPAddress->length == 4) {
00348                 sprintf(ipbuf, "%d.%d.%d.%d", oname->d.iPAddress->data[0],
00349                         oname->d.iPAddress->data[1],
00350                         oname->d.iPAddress->data[2],
00351                         oname->d.iPAddress->data[3]);
00352                 rtn = strdup(ipbuf);
00353             }
00354             else if ((oname->d.iPAddress->length == 16) ||
00355                      (oname->d.iPAddress->length == 20)) {
00356                 char *pos = ipbuf;
00357                 int   j;
00358                 for(j = 0; j < oname->d.iPAddress->length; ++j) {
00359                     *pos++ = VAL2HEX(oname->d.iPAddress->data[j]);
00360                     *pos++ = ':';
00361                 }
00362                 *pos = '\0';
00363                 rtn = strdup(ipbuf);
00364             }
00365             else
00366                 NETSNMP_LOGONCE((LOG_WARNING, "unexpected ip addr length %d\n",
00367                        oname->d.iPAddress->length));
00368 
00369             break;
00370         default:
00371             DEBUGMSGT(("openssl:cert:san", "unknown/unsupported type %d\n",
00372                        oname->type));
00373             break;
00374     }
00375     DEBUGMSGT(("9:openssl:cert:san", "san=%s\n", buf));
00376     if (buf)
00377         OPENSSL_free(buf);
00378 
00379     return rtn;
00380 }
00381 
00382 #ifndef NETSNMP_FEATURE_REMOVE_OPENSSL_CERT_GET_SUBJECTALTNAMES
00383 
00388 char *
00389 netsnmp_openssl_cert_get_subjectAltNames(X509 *ocert, char **buf, int *len)
00390 {
00391     return _cert_get_extension_id_str(ocert, NID_subject_alt_name, buf, len, 0);
00392 }
00393 #endif /* NETSNMP_FEATURE_REMOVE_OPENSSL_CERT_GET_SUBJECTALTNAMES */
00394 
00395 void
00396 netsnmp_openssl_cert_dump_extensions(X509 *ocert)
00397 {
00398     X509_EXTENSION  *extension;
00399     const char      *extension_name;
00400     char             buf[SNMP_MAXBUF_SMALL], *buf_ptr = buf, *str, *lf;
00401     int              i, num_extensions, buf_len, nid;
00402 
00403     if (NULL == ocert)
00404         return;
00405 
00406     DEBUGIF("9:cert:dump") 
00407         ;
00408     else
00409         return; /* bail if debug not enabled */
00410 
00411     num_extensions = X509_get_ext_count(ocert);
00412     if (0 == num_extensions)
00413         DEBUGMSGT(("9:cert:dump", "    0 extensions\n"));
00414     for(i = 0; i < num_extensions; i++) {
00415         extension = X509_get_ext(ocert, i);
00416         nid = OBJ_obj2nid(X509_EXTENSION_get_object(extension));
00417         extension_name = OBJ_nid2sn(nid);
00418         buf_len = sizeof(buf);
00419         str = _cert_get_extension_str_at(ocert, i, &buf_ptr, &buf_len, 0);
00420         lf = strchr(str, '\n'); /* look for multiline strings */
00421         if (NULL != lf)
00422             *lf = '\0'; /* only log first line of multiline here */
00423         DEBUGMSGT(("9:cert:dump", "    %2d: %s = %s\n", i,
00424                    extension_name, str));
00425         while(lf) { /* log remaining parts of multiline string */
00426             str = ++lf;
00427             if (*str == '\0')
00428                break;
00429             lf = strchr(str, '\n');
00430             if (NULL == lf) 
00431                 break;
00432             *lf = '\0';
00433             DEBUGMSGT(("9:cert:dump", "        %s\n", str));
00434         }
00435     }
00436 }
00437 
00438 static int _htmap[NS_HASH_MAX + 1] = {
00439     0, NID_md5WithRSAEncryption, NID_sha1WithRSAEncryption,
00440     NID_sha224WithRSAEncryption, NID_sha256WithRSAEncryption,
00441     NID_sha384WithRSAEncryption, NID_sha512WithRSAEncryption };
00442 
00443 int
00444 _nid2ht(int nid)
00445 {
00446     int i;
00447     for (i=1; i<= NS_HASH_MAX; ++i) {
00448         if (nid == _htmap[i])
00449             return i;
00450     }
00451     return 0;
00452 }
00453 
00454 #ifndef NETSNMP_FEATURE_REMOVE_OPENSSL_HT2NID
00455 int
00456 _ht2nid(int ht)
00457 {
00458     if ((ht < 0) || (ht > NS_HASH_MAX))
00459         return 0;
00460     return _htmap[ht];
00461 }
00462 #endif /* NETSNMP_FEATURE_REMOVE_OPENSSL_HT2NID */
00463 
00467 int
00468 netsnmp_openssl_cert_get_hash_type(X509 *ocert)
00469 {
00470     if (NULL == ocert)
00471         return 0;
00472 
00473     return _nid2ht(OBJ_obj2nid(ocert->sig_alg->algorithm));
00474 }
00475 
00479 char *
00480 netsnmp_openssl_cert_get_fingerprint(X509 *ocert, int alg)
00481 {
00482     u_char           fingerprint[EVP_MAX_MD_SIZE];
00483     u_int            fingerprint_len, nid;
00484     const EVP_MD    *digest;
00485     char            *result = NULL;
00486 
00487     if (NULL == ocert)
00488         return NULL;
00489 
00490     nid = OBJ_obj2nid(ocert->sig_alg->algorithm);
00491     DEBUGMSGT(("9:openssl:fingerprint", "alg %d, cert nid %d (%d)\n", alg, nid,
00492                _nid2ht(nid)));
00493         
00494     if ((-1 == alg) && nid)
00495         alg = _nid2ht(nid);
00496 
00497     switch (alg) {
00498         case NS_HASH_MD5:
00499             snmp_log(LOG_ERR, "hash type md5 not yet supported\n");
00500             return NULL;
00501             break;
00502         
00503         case NS_HASH_NONE:
00504             snmp_log(LOG_ERR, "hash type none not supported. using SHA1\n");
00507         case NS_HASH_SHA1:
00508             digest = EVP_sha1();
00509             break;
00510 
00511 #ifdef HAVE_EVP_SHA224
00512         case NS_HASH_SHA224:
00513             digest = EVP_sha224();
00514             break;
00515 
00516         case NS_HASH_SHA256:
00517             digest = EVP_sha256();
00518             break;
00519 
00520 #endif
00521 #ifdef HAVE_EVP_SHA384
00522         case NS_HASH_SHA384:
00523             digest = EVP_sha384();
00524             break;
00525 
00526         case NS_HASH_SHA512:
00527             digest = EVP_sha512();
00528             break;
00529 #endif
00530 
00531         default:
00532             snmp_log(LOG_ERR, "unknown hash algorithm %d\n", alg);
00533             return NULL;
00534     }
00535 
00536     if (_nid2ht(nid) != alg) {
00537         DEBUGMSGT(("openssl:fingerprint",
00538                    "WARNING: alg %d does not match cert alg %d\n",
00539                    alg, _nid2ht(nid)));
00540     }
00541     if (X509_digest(ocert,digest,fingerprint,&fingerprint_len)) {
00542         binary_to_hex(fingerprint, fingerprint_len, &result);
00543         if (NULL == result)
00544             snmp_log(LOG_ERR, "failed to hexify fingerprint\n");
00545         else
00546             DEBUGMSGT(("9:openssl:fingerprint", "fingerprint %s\n", result));
00547     }
00548     else
00549         snmp_log(LOG_ERR,"failed to compute fingerprint\n");
00550 
00551     return result;
00552 }
00553 
00558 netsnmp_container *
00559 netsnmp_openssl_get_cert_chain(SSL *ssl)
00560 {
00561     X509                  *ocert, *ocert_tmp;
00562     STACK_OF(X509)        *ochain;
00563     char                  *fingerprint;
00564     netsnmp_container     *chain_map;
00565     netsnmp_cert_map      *cert_map;
00566     int                    i;
00567 
00568     netsnmp_assert_or_return(ssl != NULL, NULL);
00569     
00570     if (NULL == (ocert = SSL_get_peer_certificate(ssl))) {
00572         snmp_log(LOG_ERR, "SSL peer has no certificate\n");
00573         return NULL;
00574     }
00575     DEBUGIF("9:cert:dump") {
00576         netsnmp_openssl_cert_dump_extensions(ocert);
00577     }
00578 
00579     /*
00580      * get fingerprint and save it
00581      */
00582     fingerprint = netsnmp_openssl_cert_get_fingerprint(ocert, -1);
00583     if (NULL == fingerprint)
00584         return NULL;
00585 
00586     /*
00587      * allocate cert map. Don't pass in fingerprint, since it would strdup
00588      * it and we've already got a copy.
00589      */
00590     cert_map = netsnmp_cert_map_alloc(NULL, ocert);
00591     if (NULL == cert_map) {
00592         free(fingerprint);
00593         return NULL;
00594     }
00595     cert_map->fingerprint = fingerprint;
00596     cert_map->hashType = netsnmp_openssl_cert_get_hash_type(ocert);
00597 
00598     chain_map = netsnmp_cert_map_container_create(0); /* no fp subcontainer */
00599     if (NULL == chain_map) {
00600         netsnmp_cert_map_free(cert_map);
00601         return NULL;
00602     }
00603     
00604     CONTAINER_INSERT(chain_map, cert_map);
00605 
00607     ochain = SSL_get_peer_cert_chain(ssl);
00608     if ((NULL == ochain) || (0 == sk_num((const void *)ochain))) {
00609         DEBUGMSGT(("ssl:cert:chain", "peer has no cert chain\n"));
00610     }
00611     else {
00612         /*
00613          * loop over chain, adding fingerprint / cert for each
00614          */
00615         DEBUGMSGT(("ssl:cert:chain", "examining cert chain\n"));
00616         for(i = 0; i < sk_num((const void *)ochain); ++i) {
00617             ocert_tmp = (X509*)sk_value((const void *)ochain,i);
00618             fingerprint = netsnmp_openssl_cert_get_fingerprint(ocert_tmp,
00619                                                                NS_HASH_SHA1);
00620             if (NULL == fingerprint)
00621                 break;
00622             cert_map = netsnmp_cert_map_alloc(NULL, ocert);
00623             if (NULL == cert_map) {
00624                 free(fingerprint);
00625                 break;
00626             }
00627             cert_map->fingerprint = fingerprint;
00628             cert_map->hashType = netsnmp_openssl_cert_get_hash_type(ocert_tmp);
00629 
00630             CONTAINER_INSERT(chain_map, cert_map);
00631         } /* chain loop */
00632         /*
00633          * if we broke out of loop before finishing, clean up
00634          */
00635         if (i < sk_num((const void *)ochain)) 
00636             CONTAINER_FREE_ALL(chain_map, NULL);
00637     } /* got peer chain */
00638 
00639     DEBUGMSGT(("ssl:cert:chain", "found %" NETSNMP_PRIz "u certs in chain\n",
00640                CONTAINER_SIZE(chain_map)));
00641     if (CONTAINER_SIZE(chain_map) == 0) {
00642         CONTAINER_FREE(chain_map);
00643         chain_map = NULL;
00644     }
00645 
00646     return chain_map;
00647 }
00648 
00649 /*
00650 tlstmCertSANRFC822Name "Maps a subjectAltName's rfc822Name to a
00651                   tmSecurityName.  The local part of the rfc822Name is
00652                   passed unaltered but the host-part of the name must
00653                   be passed in lower case.
00654                   Example rfc822Name Field:  FooBar@Example.COM
00655                   is mapped to tmSecurityName: FooBar@example.com"
00656 
00657 tlstmCertSANDNSName "Maps a subjectAltName's dNSName to a
00658                   tmSecurityName after first converting it to all
00659                   lower case."
00660 
00661 tlstmCertSANIpAddress "Maps a subjectAltName's iPAddress to a
00662                   tmSecurityName by transforming the binary encoded
00663                   address as follows:
00664                   1) for IPv4 the value is converted into a decimal
00665                      dotted quad address (e.g. '192.0.2.1')
00666                   2) for IPv6 addresses the value is converted into a
00667                      32-character all lowercase hexadecimal string
00668                      without any colon separators.
00669 
00670                      Note that the resulting length is the maximum
00671                      length supported by the View-Based Access Control
00672                      Model (VACM).  Note that using both the Transport
00673                      Security Model's support for transport prefixes
00674                      (see the SNMP-TSM-MIB's
00675                      snmpTsmConfigurationUsePrefix object for details)
00676                      will result in securityName lengths that exceed
00677                      what VACM can handle."
00678 
00679 tlstmCertSANAny "Maps any of the following fields using the
00680                   corresponding mapping algorithms:
00681                   | rfc822Name | tlstmCertSANRFC822Name |
00682                   | dNSName    | tlstmCertSANDNSName    |
00683                   | iPAddress  | tlstmCertSANIpAddress  |
00684                   The first matching subjectAltName value found in the
00685                   certificate of the above types MUST be used when
00686                   deriving the tmSecurityName."
00687 */
00688 char *
00689 _cert_get_san_type(X509 *ocert, int mapType)
00690 {
00691     GENERAL_NAMES      *onames;
00692     const GENERAL_NAME *oname = NULL;
00693     char               *buf = NULL, *lower = NULL;
00694     int                 count, i;
00695  
00696     onames = (GENERAL_NAMES *)X509_get_ext_d2i(ocert, NID_subject_alt_name,
00697                                                NULL, NULL );
00698     if (NULL == onames)
00699         return NULL;
00700 
00701     count = sk_GENERAL_NAME_num(onames);
00702 
00703     for (i=0 ; i <count; ++i)  {
00704         oname = sk_GENERAL_NAME_value(onames, i);
00705 
00706         if (GEN_DNS == oname->type) {
00707             if ((TSNM_tlstmCertSANDNSName == mapType) ||
00708                 (TSNM_tlstmCertSANAny == mapType)) {
00709                 lower = buf = _extract_oname( oname );;
00710                 break;
00711             }
00712         }
00713         else if (GEN_IPADD == oname->type) {
00714             if ((TSNM_tlstmCertSANIpAddress == mapType) ||
00715                 (TSNM_tlstmCertSANAny == mapType))
00716                 buf = _extract_oname(oname);
00717                 break;
00718         }
00719         else if (GEN_EMAIL == oname->type) {
00720             if ((TSNM_tlstmCertSANRFC822Name == mapType) ||
00721                 (TSNM_tlstmCertSANAny == mapType)) {
00722                 buf = _extract_oname(oname);
00723                 lower = strchr(buf, '@');
00724                 if (NULL == lower) {
00725                     DEBUGMSGT(("openssl:secname:extract",
00726                                "email %s has no '@'!\n", buf));
00727                 }
00728                 else {
00729                     ++lower;
00730                     break;
00731                 }
00732             }
00733             
00734         }
00735     } /* for loop */
00736 
00737     if (lower)
00738         for ( ; *lower; ++lower )
00739             if (isascii(*lower))
00740                 *lower = tolower(*lower);
00741     DEBUGMSGT(("openssl:cert:extension:san", "#%d type %d: %s\n", i,
00742                oname ? oname->type : -1, buf ? buf : "NULL"));
00743 
00744     return buf;
00745 }
00746 
00747 char *
00748 netsnmp_openssl_extract_secname(netsnmp_cert_map *cert_map,
00749                                 netsnmp_cert_map *peer_cert)
00750 {
00751     char       *rtn = NULL;
00752 
00753     if (NULL == cert_map)
00754         return NULL;
00755 
00756     DEBUGMSGT(("openssl:secname:extract",
00757                "checking priority %d, san of type %d for %s\n",
00758                cert_map->priority, cert_map->mapType, peer_cert->fingerprint));
00759 
00760     switch(cert_map->mapType) {
00761         case TSNM_tlstmCertSpecified:
00762             rtn = strdup(cert_map->data);
00763             break;
00764 
00765         case TSNM_tlstmCertSANRFC822Name:
00766         case TSNM_tlstmCertSANDNSName:
00767         case TSNM_tlstmCertSANIpAddress:
00768         case TSNM_tlstmCertSANAny:
00769             if (NULL == peer_cert) {
00770                 DEBUGMSGT(("openssl:secname:extract", "no peer cert for %s\n",
00771                            cert_map->fingerprint));
00772                 break;
00773             }
00774             rtn = _cert_get_san_type(peer_cert->ocert, cert_map->mapType);
00775             if (NULL == rtn) {
00776                 DEBUGMSGT(("openssl:secname:extract", "no san for %s\n",
00777                            peer_cert->fingerprint));
00778             }
00779             break;
00780 
00781         case TSNM_tlstmCertCommonName:
00782             rtn = netsnmp_openssl_cert_get_commonName(cert_map->ocert, NULL,
00783                                                        NULL);
00784             break;
00785         default:
00786             snmp_log(LOG_ERR, "cant extract secname for unknown map type %d\n",
00787                      cert_map->mapType);
00788             break;
00789     } /* switch mapType */
00790 
00791     if (rtn) {
00792         DEBUGMSGT(("openssl:secname:extract",
00793                    "found map %d, type %d for %s: %s\n", cert_map->priority,
00794                    cert_map->mapType, peer_cert->fingerprint, rtn));
00795         if (strlen(rtn) >32) {
00796             DEBUGMSGT(("openssl:secname:extract",
00797                        "secName longer than 32 chars! dropping...\n"));
00798             SNMP_FREE(rtn);
00799         }
00800     }
00801     else
00802         DEBUGMSGT(("openssl:secname:extract",
00803                    "no map of type %d for %s\n",
00804                    cert_map->mapType, peer_cert->fingerprint));
00805     return rtn;
00806 }
00807 
00808 int
00809 netsnmp_openssl_cert_issued_by(X509 *issuer, X509 *cert)
00810 {
00811     return (X509_check_issued(issuer, cert) == X509_V_OK);
00812 }
00813 
00814 
00815 #ifndef NETSNMP_FEATURE_REMOVE_OPENSSL_ERR_LOG
00816 void
00817 netsnmp_openssl_err_log(const char *prefix)
00818 {
00819     unsigned long err;
00820     for (err = ERR_get_error(); err; err = ERR_get_error()) {
00821         snmp_log(LOG_ERR,"%s: %ld\n", prefix ? prefix: "openssl error", err);
00822         snmp_log(LOG_ERR, "library=%d, function=%d, reason=%d\n",
00823                  ERR_GET_LIB(err), ERR_GET_FUNC(err), ERR_GET_REASON(err));
00824     }
00825 }
00826 #endif /* NETSNMP_FEATURE_REMOVE_OPENSSL_ERR_LOG */
00827 
00828 void
00829 netsnmp_openssl_null_checks(SSL *ssl, int *null_auth, int *null_cipher)
00830 {
00831     const SSL_CIPHER *cipher;
00832     char           *description, tmp_buf[128], *cipher_alg, *auth_alg;
00833 
00834     if (null_auth)
00835         *null_auth = -1; /* unknown */
00836     if (null_cipher)
00837         *null_cipher = -1; /* unknown */
00838     if (NULL == ssl)
00839         return;
00840 
00841     cipher = SSL_get_current_cipher(ssl);
00842     if (NULL == cipher) {
00843         DEBUGMSGTL(("ssl:cipher", "no cipher yet\n"));
00844         return;
00845     }
00846     description = SSL_CIPHER_description(NETSNMP_REMOVE_CONST(SSL_CIPHER *, cipher), tmp_buf, sizeof(tmp_buf));
00848     DEBUGMSGTL(("ssl:cipher", "current cipher: %s", tmp_buf));
00849 
00850     /*
00851      * run "openssl ciphers -v eNULL" and "openssl ciphers -v aNULL"
00852      * to see NULL encryption/authentication algorithms. e.g.
00853      *
00854      * EXP-ADH-RC4-MD5 SSLv3 Kx=DH(512) Au=None Enc=RC4(40) Mac=MD5  export
00855      * NULL-SHA        SSLv3 Kx=RSA     Au=RSA  Enc=None    Mac=SHA1
00856      */
00857     if (null_cipher) {
00858         cipher_alg = strstr(tmp_buf, "Enc=");
00859         if (cipher_alg) {
00860             cipher_alg += 4;
00861             if (strncmp(cipher_alg,"None", 4) == 0)
00862                 *null_cipher = 1;
00863             else
00864                 *null_cipher = 0;
00865         }
00866     }
00867     if (null_auth) {
00868         auth_alg = strstr(tmp_buf, "Au=");
00869         if (auth_alg) {
00870             auth_alg += 3;
00871             if (strncmp(auth_alg,"None", 4) == 0)
00872                 *null_auth = 1;
00873             else
00874                 *null_auth = 0;
00875         }
00876     }
00877 }
00878 
00879 #endif /* NETSNMP_USE_OPENSSL && HAVE_LIBSSL && !defined(NETSNMP_FEATURE_REMOVE_CERT_UTIL) */