int openconnect_check_peer_cert_hash(struct openconnect_info *vpninfo, const char *old_hash) { char sha1_text[41]; const char *fingerprint; if (strchr(old_hash, ':')) { fingerprint = openconnect_get_peer_cert_hash(vpninfo); if (!fingerprint) return -EIO; } else { unsigned char *cert; int len, i; unsigned char sha1_bin[SHA1_SIZE]; len = openconnect_get_peer_cert_DER(vpninfo, &cert); if (len < 0) return len; if (openconnect_sha1(sha1_bin, cert, len)) return -EIO; for (i = 0; i < sizeof(sha1_bin); i++) sprintf(&sha1_text[i*2], "%02x", sha1_bin[i]); fingerprint = sha1_text; } if (strcasecmp(old_hash, fingerprint)) return 1; return 0; }
int openconnect_check_peer_cert_hash(struct openconnect_info *vpninfo, const char *old_hash) { char sha1_text[41]; const char *fingerprint; unsigned min_match_len; unsigned real_min_match_len = 4; unsigned old_len, fingerprint_len; if (strchr(old_hash, ':')) { if (strncmp(old_hash, "sha1:", 5) == 0) { fingerprint = vpninfo->peer_cert_sha1; min_match_len = real_min_match_len + sizeof("sha1:")-1; } else if (strncmp(old_hash, "sha256:", 7) == 0) { fingerprint = vpninfo->peer_cert_sha256; min_match_len = real_min_match_len + sizeof("sha256:")-1; } else { vpn_progress(vpninfo, PRG_ERR, _("Unknown certificate hash: %s.\n"), old_hash); return -EIO; } if (!fingerprint) return -EIO; } else { unsigned char *cert; int len, i; unsigned char sha1_bin[SHA1_SIZE]; len = openconnect_get_peer_cert_DER(vpninfo, &cert); if (len < 0) return len; if (openconnect_sha1(sha1_bin, cert, len)) return -EIO; for (i = 0; i < sizeof(sha1_bin); i++) sprintf(&sha1_text[i*2], "%02x", sha1_bin[i]); fingerprint = sha1_text; min_match_len = real_min_match_len; } old_len = strlen(old_hash); fingerprint_len = strlen(fingerprint); /* allow partial matches */ if (old_len < fingerprint_len) { if (strncasecmp(old_hash, fingerprint, MAX(min_match_len, old_len))) { if (old_len < min_match_len) { vpn_progress(vpninfo, PRG_ERR, _("The size of the provided fingerprint is less than the minimum required (%u).\n"), real_min_match_len); } return 1; } } else { if (strcasecmp(old_hash, fingerprint)) return 1; } return 0; }
int config_lookup_host(struct openconnect_info *vpninfo, const char *host) { int i; ssize_t size; char *xmlfile; unsigned char sha1[SHA1_SIZE]; xmlDocPtr xml_doc; xmlNode *xml_node, *xml_node2; if (!vpninfo->xmlconfig) return 0; size = read_file_into_string(vpninfo, vpninfo->xmlconfig, &xmlfile); if (size == -ENOENT) { fprintf(stderr, _("Treating host \"%s\" as a raw hostname\n"), host); return 0; } else if (size <= 0) { return size; } if (openconnect_sha1(sha1, xmlfile, size)) { fprintf(stderr, _("Failed to SHA1 existing file\n")); return -1; } for (i = 0; i < SHA1_SIZE; i++) snprintf(&vpninfo->xmlsha1[i*2], 3, "%02x", sha1[i]); vpn_progress(vpninfo, PRG_DEBUG, _("XML config file SHA1: %s\n"), vpninfo->xmlsha1); xml_doc = xmlReadMemory(xmlfile, size, "noname.xml", NULL, 0); free(xmlfile); if (!xml_doc) { fprintf(stderr, _("Failed to parse XML config file %s\n"), vpninfo->xmlconfig); fprintf(stderr, _("Treating host \"%s\" as a raw hostname\n"), host); return 0; } xml_node = xmlDocGetRootElement(xml_doc); for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) { if (xml_node->type == XML_ELEMENT_NODE && !strcmp((char *)xml_node->name, "ServerList")) { for (xml_node = xml_node->children; xml_node && !vpninfo->hostname; xml_node = xml_node->next) { if (xml_node->type == XML_ELEMENT_NODE && !strcmp((char *)xml_node->name, "HostEntry")) { int match = 0; for (xml_node2 = xml_node->children; match >= 0 && xml_node2; xml_node2 = xml_node2->next) { if (xml_node2->type != XML_ELEMENT_NODE) continue; if (!match && !strcmp((char *)xml_node2->name, "HostName")) { char *content = fetch_and_trim(xml_node2); if (content && !strcmp(content, host)) match = 1; else match = -1; free(content); } else if (match && !strcmp((char *)xml_node2->name, "HostAddress")) { char *content = fetch_and_trim(xml_node2); if (content && !openconnect_parse_url(vpninfo, content)) { printf(_("Host \"%s\" has address \"%s\"\n"), host, content); } free(content); } else if (match && !strcmp((char *)xml_node2->name, "UserGroup")) { char *content = fetch_and_trim(xml_node2); if (content) { free(vpninfo->urlpath); vpninfo->urlpath = content; printf(_("Host \"%s\" has UserGroup \"%s\"\n"), host, content); } } } } } break; } } xmlFreeDoc(xml_doc); if (!vpninfo->hostname) { fprintf(stderr, _("Host \"%s\" not listed in config; treating as raw hostname\n"), host); } return 0; }
int config_lookup_host(struct openconnect_info *vpninfo, const char *host) { int fd, i; struct stat st; char *xmlfile; unsigned char sha1[SHA1_SIZE]; xmlDocPtr xml_doc; xmlNode *xml_node, *xml_node2; if (!vpninfo->xmlconfig) return 0; fd = open(vpninfo->xmlconfig, O_RDONLY); if (fd < 0) { perror(_("Open XML config file")); fprintf(stderr, _("Treating host \"%s\" as a raw hostname\n"), host); return 0; } if (fstat(fd, &st)) { perror(_("fstat XML config file")); close(fd); return -1; } xmlfile = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); if (xmlfile == MAP_FAILED) { perror(_("mmap XML config file")); close(fd); return -1; } if (openconnect_sha1(sha1, xmlfile, st.st_size)) { fprintf(stderr, _("Failed to SHA1 existing file\n")); close(fd); return -1; } for (i = 0; i < SHA1_SIZE; i++) sprintf(&vpninfo->xmlsha1[i*2], "%02x", sha1[i]); vpn_progress(vpninfo, PRG_TRACE, _("XML config file SHA1: %s\n"), vpninfo->xmlsha1); xml_doc = xmlReadMemory(xmlfile, st.st_size, "noname.xml", NULL, 0); munmap(xmlfile, st.st_size); close(fd); if (!xml_doc) { fprintf(stderr, _("Failed to parse XML config file %s\n"), vpninfo->xmlconfig); fprintf(stderr, _("Treating host \"%s\" as a raw hostname\n"), host); return 0; } xml_node = xmlDocGetRootElement(xml_doc); for (xml_node = xml_node->children; xml_node; xml_node = xml_node->next) { if (xml_node->type == XML_ELEMENT_NODE && !strcmp((char *)xml_node->name, "ServerList")) { for (xml_node = xml_node->children; xml_node && !vpninfo->hostname; xml_node = xml_node->next) { if (xml_node->type == XML_ELEMENT_NODE && !strcmp((char *)xml_node->name, "HostEntry")) { int match = 0; for (xml_node2 = xml_node->children; match >= 0 && xml_node2; xml_node2 = xml_node2->next) { if (xml_node2->type != XML_ELEMENT_NODE) continue; if (!match && !strcmp((char *)xml_node2->name, "HostName")) { char *content = (char *)xmlNodeGetContent(xml_node2); if (content && !strcmp(content, host)) match = 1; else match = -1; free(content); } else if (match && !strcmp((char *)xml_node2->name, "HostAddress")) { char *content = (char *)xmlNodeGetContent(xml_node2); if (content) { vpninfo->hostname = content; printf(_("Host \"%s\" has address \"%s\"\n"), host, content); } } else if (match && !strcmp((char *)xml_node2->name, "UserGroup")) { char *content = (char *)xmlNodeGetContent(xml_node2); if (content) { free(vpninfo->urlpath); vpninfo->urlpath = content; printf(_("Host \"%s\" has UserGroup \"%s\"\n"), host, content); } } } } } break; } } xmlFreeDoc(xml_doc); if (!vpninfo->hostname) { fprintf(stderr, _("Host \"%s\" not listed in config; treating as raw hostname\n"), host); } return 0; }